<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ignition Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/category/manufacturing-automation-intelligence/ignition/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Fri, 28 Aug 2026 15:03:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>Ignition Archives | DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Which Ignition MQTT Modules Do You Need? Transmission, Engine, and Distributor Explained</title>
		<link>https://static.dmcinfo.com/blog/50802/ignition-mqtt-modules-transmission-engine-distributor/</link>
		
		<dc:creator><![CDATA[Lovin George]]></dc:creator>
		<pubDate>Fri, 28 Aug 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[HMI and SCADA]]></category>
		<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[Ignition MQTT Modules]]></category>
		<category><![CDATA[Ignition SCADA]]></category>
		<category><![CDATA[Industrial MQTT]]></category>
		<category><![CDATA[MQTT Modules]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=50802</guid>

					<description><![CDATA[<p>Ignition supports MQTT through three modules from Cirrus Link: MQTT Transmission, MQTT Engine, and MQTT Distributor. When building an Ignition MQTT architecture for the first time, it can be hard to figure out which modules you need or where they go. Transmission publishes data to a broker, Distributor acts as the broker, and Engine subscribes [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/50802/ignition-mqtt-modules-transmission-engine-distributor/">Which Ignition MQTT Modules Do You Need? Transmission, Engine, and Distributor Explained</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Ignition supports MQTT through three modules from Cirrus Link: MQTT Transmission, MQTT Engine, and MQTT Distributor. When building an Ignition MQTT architecture for the first time, it can be hard to figure out which modules you need or where they go. Transmission publishes data to a broker, Distributor acts as the broker, and Engine subscribes to data from the broker.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--30)">I like to think of it like the marketing emails you never manage to escape. A company hands its emails to a mailing service, the mailing service keeps the list of subscribers and delivers copies to everyone on it, and you signed up once for a 10% off coupon and have received every email since. The company doesn’t know who you are, and you never talk to the company directly. In this setup, Transmission is the company, Distributor is the mailing service, and Engine is your inbox, still subscribed.</p>



<figure class="wp-block-image aligncenter size-full has-custom-border"><img fetchpriority="high" decoding="async" width="1262" height="687" src="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-6.png" alt="Ignition MQTT modules 1" class="has-border-color wp-image-50850" style="border-color:#c4c4c4;border-width:1px;border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-6.png 1262w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-6-300x163.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-6-1024x557.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-6-768x418.png 768w" sizes="(max-width: 1262px) 100vw, 1262px" /><figcaption class="wp-element-caption">Image source: Cirrus Link Solutions, <em>Getting Started: Two Ignition Architecture.</em> Retrieved from https://docs.chariot.io/display/CLD80/Getting+Started:+Two+Ignition+Architecture</figcaption></figure>



<h2 id="h-why-use-mqtt" class="wp-block-heading">Why Use MQTT?</h2>



<p class="wp-block-paragraph">MQTT is a publish-and-subscribe protocol, and that structure is the reason to use it. The central gateway maintains a single broker connection no matter how many edge sites feed into it, instead of polling every device directly. Data is also published by exception, so values only cross the network when they change, which is useful on cellular links and other constrained networks.</p>



<p class="wp-block-paragraph">MQTT alone consolidates connections into a single stream, but it says nothing about what the data looks like. A plain MQTT message is just a value on a named topic (think a string or a JSON blob), and every publisher may format it differently.</p>



<p class="wp-block-paragraph">Sparkplug adds a standard structure on top of MQTT: publishers announce everything they’re going to send when they first connect, and the broker notifies subscribers if a publisher drops offline. Ignition uses that first announcement, called a birth certificate, to build matching tags automatically instead of you mapping topics to tags by hand.</p>



<p class="wp-block-paragraph">It’s like the welcome email of the subscription that lists everything you’re about to receive. And if the company quietly shuts down, the mailing service lets you know instead of leaving you to wonder why the emails with deals stopped.</p>



<h3 id="h-mqtt-transmission" class="wp-block-heading">MQTT Transmission</h3>



<p class="wp-block-paragraph">Transmission is the publisher. It’s installed on an edge or site-level gateway that already polls local PLCs or sensors over OPC UA or native drivers. Transmission watches the tag providers or folders you select and publishes them to the broker in Sparkplug format. In the email analogy, Transmission is the company’s sending tool. The PLCs write the content, and Transmission hands it to the mailing service.</p>



<p class="wp-block-paragraph">You don’t need Transmission if a device already publishes Sparkplug natively, or if the gateway only consumes MQTT data.</p>



<h3 id="h-mqtt-distributor" class="wp-block-heading">MQTT Distributor</h3>



<p class="wp-block-paragraph">Distributor is the broker. It runs inside an Ignition gateway and accepts connections from publishers and subscribers. It’s the mailing service itself. It keeps the subscriber list and moves the mail but never writes any of it.</p>



<p class="wp-block-paragraph">Since Distributor runs inside Ignition, the module works well for proofs of concept, development environments, and smaller production systems. Larger production systems will often use a standalone broker such as Chariot or HiveMQ, especially when applications outside Ignition share the broker or when security policies require the broker and SCADA system to be separate. Transmission and Engine can connect to compatible external MQTT brokers, so Distributor is not required.</p>



<h3 id="h-mqtt-engine" class="wp-block-heading">MQTT Engine</h3>



<p class="wp-block-paragraph">Engine is the MQTT subscriber. When it’s installed on a central Ignition gateway, it connects to the broker, subscribes to Sparkplug data, and creates Ignition tags for every edge node, device, and metric it receives. Think of it like your email inbox. Everything a company sends to you shows up there, sorted and ready to read.</p>



<p class="wp-block-paragraph">Once created, these tags act like any other Ignition tags. You can display them in Ignition Perspective, historize them, and use them for alarming and scripting. Because Sparkplug carries connection state, Engine also marks tags with bad quality when an edge node goes offline.</p>



<p class="wp-block-paragraph">Engine is not the broker. It connects to the broker as a client in the same way Transmission does. If you want MQTT data to show up in Ignition, this is the module that does it.</p>



<h2 id="h-quick-guide-for-setting-up-a-basic-edge-to-central-connection" class="wp-block-heading">Quick Guide for Setting Up a Basic Edge-to-Central Connection</h2>



<p class="wp-block-paragraph">For a basic two-gateway architecture, install the Transmission module at the edge and both Distributor and Engine modules on the <a href="https://inductiveautomation.com/downloads/third-party-modules/8.3.9" target="_blank" rel="noreferrer noopener">central gateway</a>. Then:</p>



<p class="wp-block-paragraph" style="padding-bottom:0">1. <strong>Configure MQTT Distributor on the central gateway:</strong> Confirm that MQTT Distributor is enabled and listening for TCP connections on port 1883. Under <strong>Users</strong>, create a broker user or confirm that one already exists. For a production connection across an untrusted network, use TLS instead of the non-secure listener.</p>



<figure class="wp-block-image aligncenter size-full has-custom-border" style="margin-bottom:0"><img decoding="async" width="1425" height="596" src="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-1.png" alt="MQTT Distributor module" class="wp-image-50844" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-1.png 1425w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-1-300x125.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-1-1024x428.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-1-768x321.png 768w" sizes="(max-width: 1425px) 100vw, 1425px" /></figure>



<p class="wp-block-paragraph">2. <strong>Verify Engine connection on the same gateway.</strong> Under <strong>MQTT Engine &gt; Servers</strong>, confirm that the default connection points to tcp:https://static.dmcinfo.com/ and shows <strong>Connected</strong>. If authentication is enabled in Distributor, confirm that the Engine connection uses the matching credentials.</p>



<figure class="wp-block-image size-full has-custom-border"><img decoding="async" width="1428" height="619" src="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-2.png" alt="MQTT Engine module" class="wp-image-50845" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-2.png 1428w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-2-300x130.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-2-1024x444.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-2-768x333.png 768w" sizes="(max-width: 1428px) 100vw, 1428px" /></figure>



<p class="wp-block-paragraph">3. <strong>Configure Transmission connection on the edge gateway.</strong> Under <strong>MQTT Transmission &gt; Servers</strong>, point the broker connection to tcp://:1883 and confirm it shows <strong>1 of 1 connected</strong>. Afterward, create a Transmitter with the tag provider, publish path, a Sparkplug Group ID, and a unique Edge Node ID. Transmission uses the next folder beneath that path as the Device ID.</p>



<figure class="wp-block-image size-full has-custom-border"><img decoding="async" width="1465" height="401" src="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-3.png" alt="MQTT Transmission module 1" class="wp-image-50846" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-3.png 1465w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-3-300x82.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-3-1024x280.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-3-768x210.png 768w" sizes="(max-width: 1465px) 100vw, 1465px" /></figure>



<figure class="wp-block-image size-full has-custom-border"><img decoding="async" width="1963" height="693" src="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-4.png" alt="MQTT Transmission module 2" class="wp-image-50847" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-4.png 1963w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-4-300x106.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-4-1024x362.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-4-768x271.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-4-1536x542.png 1536w" sizes="(max-width: 1963px) 100vw, 1963px" /></figure>



<p class="wp-block-paragraph">4. <strong>Verify data in the Designer.</strong> Browse the MQTT Engine tag provider on the central gateway, find your Group ID and Edge Node, and confirm metrics appear and update when source values change.</p>



<figure class="wp-block-image size-full has-custom-border"><img decoding="async" width="698" height="493" src="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-5.png" alt="Ignition Tag Browser" class="has-border-color has-custom-medium-gray-neutral-2-border-color wp-image-50848" style="border-width:1px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-5.png 698w, https://static.dmcinfo.com/wp-content/uploads/2026/08/ignition-mqtt-modules-5-300x212.png 300w" sizes="(max-width: 698px) 100vw, 698px" /></figure>



<p class="wp-block-paragraph">For anything beyond a test setup, structure the edge tags as UDTs so every equipment instance publishes the same structure. New equipment can then appear in the namespace with the same layout as everything else.</p>



<h2 id="h-when-to-use-mqtt" class="wp-block-heading">When to Use MQTT</h2>



<p class="wp-block-paragraph">MQTT is a strong fit when you’re consolidating many edge sites or feeding the same data to several consumers. MQTT is also worth considering for bandwidth-constrained or congested networks because its publish-by-exception model reduces unnecessary traffic.  On one of my recent projects, we chose MQTT because of the number of devices. Terminating hundreds of individual connections at the Ignition gateway wasn’t practical, so the devices published through a broker and Ignition held a single consolidated connection.</p>



<p class="wp-block-paragraph">MQTT is not the best choice for every system. For a handful of devices on a single reliable plant network, with Ignition as the only consumer, a direct OPC UA connection is simpler. The Gateway Network also handles tag, alarm, and history sharing between a small number of Ignition gateways without extra infrastructure. And MQTT means another service to configure, secure, and monitor.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)">Once each module’s responsibility is clear, it becomes easier to place components, troubleshoot connections, and scale the architecture. The same pattern can also support a unified namespace, in which sites publish to a shared structure consumed by SCADA, MES, analytics, and cloud applications.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step">Have an upcoming Ignition project? DMC can help you take the next step.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">DMC&#8217;s <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/" target="_blank" rel="noreferrer noopener">Automation</a> experts develop <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/" target="_blank" rel="noreferrer noopener">scalable Ignition</a> and <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/industrial-iot/" target="_blank" rel="noreferrer noopener">industrial MQTT solutions</a> that connect field equipment, edge gateways, and enterprise applications.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/50802/ignition-mqtt-modules-transmission-engine-distributor/">Which Ignition MQTT Modules Do You Need? Transmission, Engine, and Distributor Explained</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>DMC Wins &#8216;Best Error Handling&#8217; in Preliminary Round of the 2026 ICC Build-a-Thon</title>
		<link>https://static.dmcinfo.com/blog/49324/dmc-wins-best-error-handling-2026-icc-build-a-thon/</link>
		
		<dc:creator><![CDATA[Lovin George]]></dc:creator>
		<pubDate>Mon, 03 Aug 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[HMI and SCADA]]></category>
		<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=49324</guid>

					<description><![CDATA[<p>This July, DMC competed in the preliminary round of Inductive Automation’s 2026 Build-a-Thon ahead of this year’s Inductive Community Conference (ICC), an event DMC&#8217;s Automation team is no stranger to. Our challenge was to build a world-class alarm analysis dashboard entirely in Ignition Perspective. This year’s primary round was unique in that we had eight [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/49324/dmc-wins-best-error-handling-2026-icc-build-a-thon/">DMC Wins &#8216;Best Error Handling&#8217; in Preliminary Round of the 2026 ICC Build-a-Thon</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">This July, DMC competed in the preliminary round of Inductive Automation’s 2026 Build-a-Thon ahead of this year’s <a href="https://icc.inductiveautomation.com/">Inductive Community Conference</a> (ICC), an <a href="https://static.dmcinfo.com/blog/15927/dmc-wins-the-2024-icc-build-a-thon/">event DMC&#8217;s Automation team</a> is no stranger to.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--20)">Our challenge was to build a world-class alarm analysis dashboard entirely in <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">Ignition Perspective</a>. This year’s primary round was unique in that we had eight consecutive hours to plan, develop, test, and submit the application.</p>



<h2 id="h-the-alarm-intelligence-center" class="wp-block-heading">The Alarm Intelligence Center</h2>



<figure class="wp-block-image size-large has-custom-border" style="margin-bottom:var(--wp--preset--spacing--50)"><img decoding="async" width="1024" height="576" src="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-1-1024x576.png" alt="Alarm intelligence center." class="wp-image-49332" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-1-1024x576.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-1-300x169.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-1-768x432.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-1-1536x864.png 1536w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-1.png 1921w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Our goal was to build more than a list of alarms. While Ignition’s standard alarm status and journal tables serve many applications well, we wanted our dashboard to help operators understand what the alarm data was telling them.</p>



<p class="wp-block-paragraph">The result was the Alarm Intelligence Center, an operator-focused dashboard organized around three questions:</p>



<ul class="wp-block-list">
<li style="padding-bottom:var(--wp--preset--spacing--20)">How healthy is the facility?</li>



<li style="padding-bottom:var(--wp--preset--spacing--30)">Which alarms or sources need attention?</li>



<li>Is performance improving over time?</li>
</ul>



<h2 id="h-the-implementation" class="wp-block-heading">The Implementation</h2>



<p class="wp-block-paragraph">We focused on creating a slick, intuitive dashboard that made both real-time alarm data and historical performance easy to understand at a glance.</p>



<p class="wp-block-paragraph">On the backend, we used named queries and custom scripting to analyze current and historical alarm events. Using EEMUA-informed alarm management metrics, we turned that analysis into information operators could act on, including:</p>



<ul class="wp-block-list">
<li style="padding-bottom:var(--wp--preset--spacing--20)">Alarm rate and time spent in flood.</li>



<li style="padding-bottom:var(--wp--preset--spacing--20)">Average time to acknowledge.</li>



<li style="padding-bottom:var(--wp--preset--spacing--20)">Standing and chattering alarms.</li>



<li style="padding-bottom:var(--wp--preset--spacing--20)">Priority distribution and historical trends.</li>



<li style="padding-bottom:var(--wp--preset--spacing--30)">A Pareto view identifying the sources responsible for most of the alarm load.</li>
</ul>



<div class="wp-block-cb-carousel-v2 cb-carousel-block cb-single-slide" data-cb-slides-per-view="1" data-cb-slides-per-group="1" data-cb-space-between="15" data-cb-speed="300" data-cb-navigation="true" data-cb-pagination="true" data-cb-loop="true" data-cb-autoplay="true" data-cb-autoplay-speed="3000" data-cb-pause-on-mouse-enter="true" data-cb-breakpoints="{&quot;768&quot;:{&quot;slidesPerView&quot;:1,&quot;slidesPerGroup&quot;:1}}"><div class="swiper"><div class="cb-wrapper swiper-wrapper">
<div class="wp-block-cb-slide-v2 cb-slide swiper-slide">
<figure class="wp-block-image aligncenter size-full has-custom-border" style="margin-bottom:0"><img decoding="async" width="1920" height="1077" src="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-2.png" alt="Alarm center sources." class="wp-image-49335" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-2.png 1920w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-2-300x168.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-2-1024x574.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-2-768x431.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-2-1536x862.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></figure>
</div>



<div class="wp-block-cb-slide-v2 cb-slide swiper-slide">
<figure class="wp-block-image size-full has-custom-border"><img decoding="async" width="1920" height="1077" src="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-3.png" alt="Daily alarm load." class="wp-image-49336" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-3.png 1920w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-3-300x168.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-3-1024x574.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-3-768x431.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-3-1536x862.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></figure>
</div>
</div></div><div class="cb-pagination swiper-pagination"></div><div class="cb-button-prev swiper-button-prev"></div><div class="cb-button-next swiper-button-next"></div></div>



<p class="wp-block-paragraph" style="padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--40)">We also built custom alarm status and alarm history tables that fit seamlessly with the dashboard’s visual style. The tables provided simplified filtering and controls for viewing alarm details, acknowledging active alarms, and shelving them.</p>



<div class="wp-block-cb-carousel-v2 cb-carousel-block cb-single-slide" data-cb-slides-per-view="1" data-cb-slides-per-group="1" data-cb-space-between="15" data-cb-speed="300" data-cb-navigation="true" data-cb-pagination="true" data-cb-loop="true" data-cb-autoplay="true" data-cb-autoplay-speed="3000" data-cb-pause-on-mouse-enter="true" data-cb-breakpoints="{&quot;768&quot;:{&quot;slidesPerView&quot;:1,&quot;slidesPerGroup&quot;:1}}"><div class="swiper"><div class="cb-wrapper swiper-wrapper">
<div class="wp-block-cb-slide-v2 cb-slide swiper-slide">
<figure class="wp-block-image aligncenter size-full has-custom-border" style="margin-bottom:0"><img decoding="async" width="1918" height="1081" src="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-4.png" alt="Active alarm states." class="wp-image-49339" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-4.png 1918w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-4-300x169.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-4-1024x577.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-4-768x433.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-4-1536x866.png 1536w" sizes="(max-width: 1918px) 100vw, 1918px" /></figure>
</div>



<div class="wp-block-cb-slide-v2 cb-slide swiper-slide">
<figure class="wp-block-image size-full has-custom-border"><img decoding="async" width="1918" height="1078" src="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-5.png" alt="Alarm history dashboard." class="wp-image-49340" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-5.png 1918w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-5-300x169.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-5-1024x576.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-5-768x432.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/07/dmc-wins-best-error-handling-5-1536x863.png 1536w" sizes="(max-width: 1918px) 100vw, 1918px" /></figure>
</div>
</div></div><div class="cb-pagination swiper-pagination"></div><div class="cb-button-prev swiper-button-prev"></div><div class="cb-button-next swiper-button-next"></div></div>



<p class="wp-block-paragraph">The result was a polished, standards-driven dashboard that helped operators quickly understand system health, identify problem areas, and decide where to focus their attention.</p>



<p class="wp-block-paragraph">DMC is proud to share that our submission received the <strong>Best Error Handling </strong>award.</p>



<p class="wp-block-paragraph">The experience demonstrated what DMC does best: bring the right people together, quickly turn ideas into action, and deliver a polished solution under a demanding deadline.</p>



<p class="wp-block-paragraph">Check out the project on <a href="https://inductiveautomation.com/exchange/2986" target="_blank" rel="noreferrer noopener">Ignition Exchange</a>.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step">Have an upcoming project? DMC can help you take the next step.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">DMC helps manufacturers build intuitive <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">SCADA applications</a> that turn operational data into actionable information. Contact us to learn more about our Ignition programming and <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/">automation solutions</a>.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/49324/dmc-wins-best-error-handling-2026-icc-build-a-thon/">DMC Wins &#8216;Best Error Handling&#8217; in Preliminary Round of the 2026 ICC Build-a-Thon</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Step-by-Step Guide: Building a CSS Skeleton in Ignition Perspective</title>
		<link>https://static.dmcinfo.com/blog/45780/ignition-perspective-loading-skeleton-css/</link>
		
		<dc:creator><![CDATA[Austin D'Acquisto]]></dc:creator>
		<pubDate>Thu, 18 Jun 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[Ignition Perspective]]></category>
		<category><![CDATA[UX/UI]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=45780</guid>

					<description><![CDATA[<p>When an Ignition Perspective view takes a moment to load, a blank area can make the page feel unfinished or broken, even if everything is working normally. A loading skeleton solves that by showing a placeholder version of the content before the real data loads. Instead of staring at an empty space, the user sees [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/45780/ignition-perspective-loading-skeleton-css/">Step-by-Step Guide: Building a CSS Skeleton in Ignition Perspective</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">When an Ignition Perspective view takes a moment to load, a blank area can make the page feel unfinished or broken, even if everything is working normally.</p>



<p class="wp-block-paragraph">A loading skeleton solves that by showing a placeholder version of the content before the real data loads. Instead of staring at an empty space, the user sees the shape of the card, chart, or widget that is about to appear.</p>



<p class="wp-block-paragraph">In this post, I will show a straightforward way to build a shimmer loading skeleton in Ignition Perspective using a lightweight skeleton view, a loading Boolean, and a custom style class in the project stylesheet. No JavaScript or custom module is needed.</p>



<h2 class="wp-block-heading" id="h-what-we-are-building">What We are Building</h2>



<ul class="wp-block-list">
<li>Create a normal embedded view for the real content.</li>



<li>Create a second embedded view that is structurally identical but uses placeholder components instead of real data.</li>



<li>Apply the shimmer-style class to those placeholder components.</li>



<li>Toggle between the real view and the skeleton view using a loading Boolean.</li>
</ul>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--30)">This works well for KPI cards, summary widgets, charts, tables, and other dashboard elements.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-0e47273b wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="377" height="162" src="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-1.png" alt="Screenshot of a loading screen in Ignition Perspective without CSS overlay." class="wp-image-45828" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;aspect-ratio:2.327272727272727;object-fit:cover;width:400px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-1.png 377w, https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-1-300x129.png 300w" sizes="(max-width: 377px) 100vw, 377px" /><figcaption class="wp-element-caption"><em>Figure 1: Example metrics widget in its loaded state.</em></figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="377" height="162" src="https://static.dmcinfo.com/wp-content/uploads/2026/06/main-widget-pretty-skeleton.gif" alt="Gif showing widgets with a CSS loading skeleton, indicating elements are still loading." class="wp-image-45878" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;width:400px"/><figcaption class="wp-element-caption"><em>Figure 2: The same widget showing the skeleton shimmer during loading.</em></figcaption></figure>
</div>
</div>



<h2 class="wp-block-heading">Step 1: Create a Skeleton Version of the View</h2>



<p class="wp-block-paragraph">Start with your normal view. For example, suppose you already have a card view called MetricCard. Create a second version of it called MetricCardSkeleton.</p>



<p class="wp-block-paragraph">The skeleton version should keep the same overall layout as the real one: the same containers, spacing, padding, alignment, and approximate component sizes.</p>



<p class="wp-block-paragraph">The goal is not to redesign the card. The goal is to make a lightweight placeholder that occupies roughly the same space as the real content.</p>



<p class="wp-block-paragraph">For example, if the real card includes a title, a large OEE number, and a small subtitle, the skeleton version should include placeholders in the same locations.</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="917" height="199" src="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-2.png" alt="Screenshot of a panel outlining a MetricCardSkeleton element with child elements including a header, metric value (LblMetric), and a trend indicator." class="has-border-color has-custom-medium-gray-neutral-2-border-color wp-image-45840" style="border-width:1px;border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;width:778px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-2.png 917w, https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-2-300x65.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-2-768x167.png 768w" sizes="(max-width: 917px) 100vw, 917px" /><figcaption class="wp-element-caption"><em>Figure 3: Skeleton view created by duplicating the original card and disabling its live bindings.</em></figcaption></figure>



<h2 class="wp-block-heading">Step 2: Use Static Placeholder Text for Sizing</h2>



<p class="wp-block-paragraph">For text-based placeholders, I used normal Label components and applied a custom style class to them.</p>



<p class="wp-block-paragraph">The label text itself is just there to help with spacing and sizing. It does not need to be meaningful, and it should not be bound to live data.</p>



<p class="wp-block-paragraph">For example, if the actual OEE typically shows 47.7%, the skeleton label might simply show 88.8%. That gives the label a realistic width and height while keeping the skeleton lightweight.</p>



<p class="wp-block-paragraph">The same idea applies to titles. You might use a short static label value just to preserve the shape of the final layout.</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="405" height="191" src="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-3.png" alt="Screenshot of a loading screen at 88.8%" class="wp-image-45843" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;aspect-ratio:2.120432671833745;width:401px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-3.png 405w, https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-3-300x141.png 300w" sizes="(max-width: 405px) 100vw, 405px" /><figcaption class="wp-element-caption"><em>Figure 4: Static placeholder values preserve the size and spacing of the final content</em>.</figcaption></figure>



<h2 class="wp-block-heading">Step 3: Add a Loading Boolean</h2>



<p class="wp-block-paragraph">This is the part that makes the whole pattern actually usable.</p>



<p class="wp-block-paragraph">You need some Boolean value that tells Perspective whether the real content is ready yet. A simple example would be <code>view.custom.isLoading</code>.</p>



<p class="wp-block-paragraph">Set that Boolean however it makes sense for your view. Common options include setting it true until a query returns, until required params are present, until a custom property is populated, or until a dataset or object has usable data.</p>



<p class="wp-block-paragraph">For a simple setup, <code>isLoading</code> should be true while the data is not ready and false once the data is ready.</p>



<p class="wp-block-paragraph">Then bind visibility like this:</p>



<ul class="wp-block-list">
<li>Real view visible when <code>!view.custom.isLoading</code></li>



<li>Skeleton view visible when <code>view.custom.isLoading</code></li>
</ul>



<p class="wp-block-paragraph">This makes the skeleton show first, then disappear once the real content is ready.</p>



<h2 class="wp-block-heading" id="h-step-4-add-a-css-shimmer-style-class-in-perspective">Step 4: Add a CSS Shimmer Style Class in Perspective</h2>



<p class="wp-block-paragraph">In Perspective, style classes can be created in the project stylesheet. I used a single general-purpose class for shimmer text placeholders.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">CSS</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>:root{
  --sk-base:   #FFFFFF1A;
  --sk-radius: 8px;
  --sk-clear:  #FFFFFF00;
}

@keyframes shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

.psc-skeletonTextShimmer {
  background:
    linear-gradient(
      90deg,
      var(--sk-clear) 0%,
      var(--sk-clear) 35%,
      var(--sk-base) 50%,
      var(--sk-clear) 65%,
      var(--sk-clear) 100%
    ),
    var(--sk-base);
  background-size: 200% 100%;
  background-repeat: no-repeat;
  border-radius: var(--sk-radius);
  min-height: 14px;
  animation: shimmer 1.4s ease-in-out infinite both;
  color: #FFFFFF00;
  user-select: none;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D7BA7D">:root</span><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">--sk-base</span><span style="color: #D4D4D4">:   </span><span style="color: #CE9178">#FFFFFF1A</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">--sk-radius</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">8px</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">--sk-clear</span><span style="color: #D4D4D4">:  </span><span style="color: #CE9178">#FFFFFF00</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">@keyframes</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">shimmer</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  from { </span><span style="color: #9CDCFE">background-position</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">200%</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">  to   { </span><span style="color: #9CDCFE">background-position</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">-200%</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D7BA7D">.psc-skeletonTextShimmer</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">background</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">linear-gradient</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #B5CEA8">90deg</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #DCDCAA">var</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">--sk-clear</span><span style="color: #D4D4D4">) </span><span style="color: #B5CEA8">0%</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #DCDCAA">var</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">--sk-clear</span><span style="color: #D4D4D4">) </span><span style="color: #B5CEA8">35%</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #DCDCAA">var</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">--sk-base</span><span style="color: #D4D4D4">) </span><span style="color: #B5CEA8">50%</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #DCDCAA">var</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">--sk-clear</span><span style="color: #D4D4D4">) </span><span style="color: #B5CEA8">65%</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #DCDCAA">var</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">--sk-clear</span><span style="color: #D4D4D4">) </span><span style="color: #B5CEA8">100%</span></span>
<span class="line"><span style="color: #D4D4D4">    ),</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">var</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">--sk-base</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">background-size</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">200%</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">100%</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">background-repeat</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">no-repeat</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">border-radius</span><span style="color: #D4D4D4">: </span><span style="color: #DCDCAA">var</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">--sk-radius</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">min-height</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">14px</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">animation</span><span style="color: #D4D4D4">: shimmer </span><span style="color: #B5CEA8">1.4s</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">ease-in-out</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">infinite</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">both</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">color</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">#FFFFFF00</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">user-select</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">none</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">A quick Ignition-specific note: if your Perspective style class is named <code>skeletonTextShimmer</code>, the selector in the stylesheet needs the <code>.psc-</code> prefix: <code>.psc-skeletonTextShimmer</code>.</p>



<p class="wp-block-paragraph">For a deeper dive into this code, see the section <strong><a href="#how-the-css-works">How the CSS Works</a></strong>.</p>



<h2 class="wp-block-heading" id="h-step-5-apply-the-style-class-to-placeholder-labels">Step 5: Apply the Style Class to Placeholder Labels</h2>



<p class="wp-block-paragraph">In the skeleton view, apply the style class to the labels you want to shimmer.</p>



<pre class="wp-block-code"><code>props.style.classes = skeletonTextShimmer</code></pre>



<p class="wp-block-paragraph">You can keep normal label styling for things like:</p>



<ul class="wp-block-list">
<li>font size</li>



<li>font weight</li>



<li>margin</li>



<li>padding</li>



<li>alignment</li>
</ul>



<p class="wp-block-paragraph">The text itself becomes transparent due to CSS, but the label retains its size and layout behavior. That is what makes this pattern so convenient: you are still working with ordinary Perspective components, just styled to look like placeholders.</p>



<p class="wp-block-paragraph"><strong>Tip:</strong> If the shimmer does not appear right away in the Designer, try closing and reopening the view.</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="773" height="243" src="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-4.png" alt="Screenshot showing a view of the CSS panel applying a shimmer overlay to widgets loading in the front end." class="has-border-color has-custom-medium-gray-neutral-2-border-color wp-image-45853" style="border-width:1px;border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;aspect-ratio:3.1633736172389537;width:778px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-4.png 773w, https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-4-300x94.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/06/ignition-perspective-css-loading-skeleton-4-768x241.png 768w" sizes="(max-width: 773px) 100vw, 773px" /><figcaption class="wp-element-caption"><em>Figure 5: Apply the skeletonTextShimmer style class to the placeholder label in the Property Editor</em>.</figcaption></figure>



<h2 class="wp-block-heading">Step 6: Show the Skeleton While the Real View Loads</h2>



<p class="wp-block-paragraph">A simple and maintainable way to do this is to use two embedded views in a parent container: one embedded view for <code>MetricCard</code> and one embedded view for <code>MetricCardSkeleton</code>. Then bind each view’s visible property to your loading Boolean.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>Skeleton embedded view:
visible = view.custom.isLoading

Real embedded view:
visible = !view.custom.isLoading</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">Skeleton</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">embedded</span><span style="color: #D4D4D4"> </span><span style="color: #C8C8C8">view</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #9CDCFE">visible</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">view</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">custom</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">isLoading</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">Real</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">embedded</span><span style="color: #D4D4D4"> </span><span style="color: #C8C8C8">view</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #9CDCFE">visible</span><span style="color: #D4D4D4"> = !</span><span style="color: #9CDCFE">view</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">custom</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">isLoading</span></span></code></pre></div>



<p class="wp-block-paragraph">That gives you a very readable setup: when loading is true, show the skeleton; when loading is false, show the real widget. This is often easier to maintain than trying to make one view serve both purposes.</p>



<h2 class="wp-block-heading">Why This Works Well</h2>



<p class="wp-block-paragraph">This pattern gives the user immediate visual structure instead of a blank area.</p>



<p class="wp-block-paragraph">It also reduces layout shift because the skeleton uses the same approximate spacing as the real content.</p>



<p class="wp-block-paragraph">Just as importantly, it stays simple. You are not adding much scripting or frontend complexity. You are duplicating the layout, replacing live content with static placeholders, toggling visibility with a Boolean, and using one reusable CSS class.</p>



<h2 class="wp-block-heading">A Few Practical Tips</h2>



<p class="wp-block-paragraph"><strong>Keep the skeleton lightweight:</strong> Do not bind the placeholder labels to live data. Their job is just to hold space and show the shimmer effect.</p>



<p class="wp-block-paragraph"><strong>Match the real layout closely:</strong> The closer the skeleton matches the final card, the smoother the transition feels.</p>



<p class="wp-block-paragraph">Use realistic placeholder lengths: For percentages, use something like 88.8%. For short titles, use placeholder text of similar length. That helps preserve spacing.</p>



<p class="wp-block-paragraph"><strong>Hide overflow if needed:</strong> If a placeholder label could get awkwardly sized, setting overflow-related text styling can help keep the skeleton clean.</p>



<h2 class="wp-block-heading" id="how-the-css-works">How the CSS Works</h2>



<p class="wp-block-paragraph">If you mainly want the implementation, you can stop after applying the class and wiring up the loading Boolean. If you are curious about how the shimmer works, here is the breakdown.</p>



<h3 class="wp-block-heading">Root Variables</h3>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">CSS</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>:root{
  --sk-base:   #FFFFFF1A;
  --sk-radius: 8px;
  --sk-clear:  #FFFFFF00;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D7BA7D">:root</span><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">--sk-base</span><span style="color: #D4D4D4">:   </span><span style="color: #CE9178">#FFFFFF1A</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">--sk-radius</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">8px</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">--sk-clear</span><span style="color: #D4D4D4">:  </span><span style="color: #CE9178">#FFFFFF00</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">These are reusable values for the skeleton effect.</p>



<ul class="wp-block-list">
<li><code>--sk-base</code> is the main placeholder color</li>



<li><code>--sk-radius</code> keeps the skeleton corners rounded</li>



<li><code>--sk-clear</code> is a fully transparent color used inside the shimmer gradient</li>
</ul>



<p class="wp-block-paragraph">Using CSS variables makes it easier to tweak the look later without rewriting the whole class.</p>



<h3 class="wp-block-heading">Keyframe Animation</h3>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">CSS</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>@keyframes shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">@keyframes</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">shimmer</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  from { </span><span style="color: #9CDCFE">background-position</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">200%</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">  to   { </span><span style="color: #9CDCFE">background-position</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">-200%</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">This animation moves the background image from right to left.</p>



<p class="wp-block-paragraph">The shimmer effect is not a separate moving object. It is just the background gradient sliding across the component over time.</p>



<h3 class="wp-block-heading">The Background Layers</h3>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">CSS</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>background:
  linear-gradient(
    90deg,
    var(--sk-clear) 0%,
    var(--sk-clear) 35%,
    var(--sk-base) 50%,
    var(--sk-clear) 65%,
    var(--sk-clear) 100%
  ),
  var(--sk-base);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">background:</span></span>
<span class="line"><span style="color: #D4D4D4">  linear-gradient(</span></span>
<span class="line"><span style="color: #D4D4D4">    90deg,</span></span>
<span class="line"><span style="color: #D4D4D4">    var(--sk-clear) 0%,</span></span>
<span class="line"><span style="color: #D4D4D4">    var(--sk-clear) 35%,</span></span>
<span class="line"><span style="color: #D4D4D4">    var(--sk-base) 50%,</span></span>
<span class="line"><span style="color: #D4D4D4">    var(--sk-clear) 65%,</span></span>
<span class="line"><span style="color: #D4D4D4">    var(--sk-clear) 100%</span></span>
<span class="line"><span style="color: #D4D4D4">  ),</span></span>
<span class="line"><span style="color: #D4D4D4">  var(--sk-base);</span></span></code></pre></div>



<p class="wp-block-paragraph">There are two background layers here:</p>



<ol class="wp-block-list">
<li>A <code>linear gradient</code> (…) that creates the moving shimmer band</li>



<li>A solid var(<code>--sk-base</code>) layer underneath it</li>
</ol>



<p class="wp-block-paragraph">The gradient is mostly transparent, with a slightly visible band in the middle. As it moves, that band creates the shimmer effect.</p>



<h3 class="wp-block-heading">Background Size and Repeat</h3>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">CSS</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>background-size: 200% 100%;
background-repeat: no-repeat;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">background-size</span><span style="color: #D4D4D4">: 200% 100%;</span></span>
<span class="line"><span style="color: #569CD6">background-repeat</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">no-repeat</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>background-size</code> makes the animated gradient wider than the component itself, which gives the shimmer room to move across the element instead of appearing static.</p>



<p class="wp-block-paragraph"><code>background-repeat</code>: no-repeat keeps the gradient from tiling in ways that look messy or unnatural.</p>



<p class="wp-block-paragraph"><code>border-radius </code>keeps the skeleton shape visually aligned with the rest of the UI.</p>



<p class="wp-block-paragraph"><code>min-height </code>helps prevent small labels from collapsing too much.</p>



<p class="wp-block-paragraph">The animation line applies the shimmer keyframes and controls the speed, easing, and repetition.</p>



<h3 class="wp-block-heading">Transparent Text and Text Selection</h3>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">CSS</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>color: #FFFFFF00;
user-select: none;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">color: </span><span style="color: #F44747">#FFFFFF00;</span></span>
<span class="line"><span style="color: #569CD6">user-select</span><span style="color: #D4D4D4">: none;</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>color</code> hides the label text without removing the label itself.</p>



<p class="wp-block-paragraph">That is important because the label is still doing layout work for us. It keeps its width, height, margins, padding, and font-based sizing, but the user sees only the animated background.</p>



<p class="wp-block-paragraph"><code>user-select: none</code> prevents users from accidentally highlighting invisible text while the skeleton is visible.</p>



<h2 class="wp-block-heading">Final Thoughts</h2>



<p class="wp-block-paragraph">This is a small UX improvement, but it makes a Perspective project feel much more polished.</p>



<p class="wp-block-paragraph">Instead of showing a blank region while data loads, you can show a placeholder that matches the real layout and communicates that the screen is actively loading.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--40)">The main pieces are simple: a real view, a skeleton view, static placeholder components, a loading Boolean, and one shimmer style class. Once you set up the pattern, it becomes easy to reuse across the rest of the project.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Ready to take your Ignition Perspective project to the next level?</strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Contact DMC to learn how our <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/">Automation</a> team can help you build polished, high-performance applications in <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">Ignition</a>.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/45780/ignition-perspective-loading-skeleton-css/">Step-by-Step Guide: Building a CSS Skeleton in Ignition Perspective</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Ignition Tricks: Improving Exception Handling and Error Logging</title>
		<link>https://static.dmcinfo.com/blog/44984/ignition-exception-handling/</link>
		
		<dc:creator><![CDATA[Isabelle Chan]]></dc:creator>
		<pubDate>Mon, 15 Jun 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[ignition]]></category>
		<category><![CDATA[Ignition 8.3]]></category>
		<category><![CDATA[Programming]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=44984</guid>

					<description><![CDATA[<p>What Are Exceptions in Ignition and Why Should I Care? Exceptions are unexpected events that a program cannot take care of on its own, and stop the program from executing. Exceptions can be caused by a wide range of factors, leaving the user wondering why the system isn’t working when improperly managed. When an exception [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/44984/ignition-exception-handling/">Ignition Tricks: Improving Exception Handling and Error Logging</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-what-are-exceptions-in-ignition-and-why-should-i-care">What Are Exceptions in Ignition and Why Should I Care?</h2>



<p class="wp-block-paragraph">Exceptions are unexpected events that a program cannot take care of on its own, and stop the program from executing. Exceptions can be caused by a wide range of factors, leaving the user wondering why the system isn’t working when improperly managed.</p>



<p class="wp-block-paragraph">When an exception occurs, the event details are laid out in an exception object, which can be used to better handle the event. By learning to use these details and handle exceptions, developers can write more robust functions, provide useful error messages when things go wrong, and flag conditions that could cause problems downstream.</p>



<h2 class="wp-block-heading">How to Approach Exception Handling</h2>



<p class="wp-block-paragraph">When handling exceptions, DMC encourages engineers and programmers to stick by these three guidelines:</p>



<ol class="wp-block-list">
<li>Let the code fail but rewrite the error message so that it is more helpful.</li>



<li>Use the DMC pop-up library to display exceptions as errors to the users.</li>



<li>Set up the code so that the system handles known and unknown errors consistently.</li>
</ol>



<h2 class="wp-block-heading" id="h-handling-exceptions">Handling Exceptions</h2>



<p class="wp-block-paragraph">Exceptions are handled by wrapping error-prone code in a <code>try/except</code> block. There are several types of except statements that can accomplish different things.</p>



<p class="wp-block-paragraph">Because Ignition uses Jython, a Java implementation of Python, it is also important to handle Java <code>exception</code> types where applicable.</p>



<h3 class="wp-block-heading">Understanding Python Syntax for Exception Handling</h3>



<p class="wp-block-paragraph">In Python, there are four main keywords for handling exceptions:</p>



<ul class="wp-block-list">
<li><strong>Try: </strong>contains error-prone code</li>



<li><strong>Except: </strong>catches and handles errors if they occur</li>



<li><strong>Else: </strong>runs if the try block completes successfully</li>



<li><strong>Finally:</strong> always runs, regardless of what occurs earlier</li>
</ul>



<p class="wp-block-paragraph">The core of exception handling occurs in the <code>try</code> and <code>except</code> statements, so we will focus on those in the following examples.</p>



<h3 class="wp-block-heading">Basic Exception</h3>



<p class="wp-block-paragraph">This example uses the most basic implementation of a <code>try/except</code> statement. You know that an error occurred, but you don’t know anything about the error. Not very useful.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>try:
  output = dividend / divisor
  success = True
except:
  success = False
  errorMessage = 'An error occurred while dividing'</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  output = dividend / divisor</span></span>
<span class="line"><span style="color: #D4D4D4">  success = </span><span style="color: #569CD6">True</span></span>
<span class="line"><span style="color: #C586C0">except</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  success = </span><span style="color: #569CD6">False</span></span>
<span class="line"><span style="color: #D4D4D4">  errorMessage = </span><span style="color: #CE9178">&apos;An error occurred while dividing&apos;</span></span></code></pre></div>



<h3 class="wp-block-heading">Catch Python Exceptions</h3>



<p class="wp-block-paragraph">You can include the base exception type in the syntax to get the error message or filter for specific error types. It is best practice to look out for specific exception types. In the example below, we catch the <code>ZeroDivisionError</code> type and rewrite the error message so it is more human-readable. Notice how you can include multiple <code>except</code> statements! This way, you can filter for known exceptions and still catch others that may occur during execution of the code.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>try:
  output = dividend / divisor
except ZeroDivisionError as e:
  errorMessage = 'Cannot divide by zero: {}'.format(e.message)
except Exception as e:
  errorMessage = 'Division error: {}'.format(e.message)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  output = dividend / divisor</span></span>
<span class="line"><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ZeroDivisionError</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> e:</span></span>
<span class="line"><span style="color: #D4D4D4">  errorMessage = </span><span style="color: #CE9178">&apos;Cannot divide by zero: </span><span style="color: #569CD6">{}</span><span style="color: #CE9178">&apos;</span><span style="color: #D4D4D4">.format(e.message)</span></span>
<span class="line"><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Exception</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> e:</span></span>
<span class="line"><span style="color: #D4D4D4">  errorMessage = </span><span style="color: #CE9178">&apos;Division error: </span><span style="color: #569CD6">{}</span><span style="color: #CE9178">&apos;</span><span style="color: #D4D4D4">.format(e.message)</span></span></code></pre></div>



<h3 class="wp-block-heading">Catch Python and Java Exceptions</h3>



<p class="wp-block-paragraph">Because Ignition uses Jython, a Java implementation of Python, we should also handle Java exception types that might occur during queries, casting, or other scenarios.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import java.lang.Exception as JavaException

try:
  output = dividend / divisor
except (Exception, JavaException) as e:
  errorMessage = 'Division error: {}'.format(e.message)  </textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> java.lang.Exception </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> JavaException</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  output = dividend / divisor</span></span>
<span class="line"><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> (</span><span style="color: #4EC9B0">Exception</span><span style="color: #D4D4D4">, JavaException) </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> e:</span></span>
<span class="line"><span style="color: #D4D4D4">  errorMessage = </span><span style="color: #CE9178">&apos;Division error: </span><span style="color: #569CD6">{}</span><span style="color: #CE9178">&apos;</span><span style="color: #D4D4D4">.format(e.message)  </span></span></code></pre></div>



<h2 class="wp-block-heading">Displaying and Logging Exceptions</h2>



<h3 class="wp-block-heading">Displaying</h3>



<p class="wp-block-paragraph">DMC’s pop-up library includes functions for automatically displaying exception message pop-ups in Perspective without requiring the declaration of a specific exception type. The pop-ups in this library can display simplified and detailed versions of the error, providing both user-friendly and developer-friendly messages.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import traceback
logger = system.util.getLogger('Test Function')

try:
  myFunction(inputA,inputB,inputC)
except Exception as e:
  logger.error(traceback.format_exc(e))
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> traceback</span></span>
<span class="line"><span style="color: #D4D4D4">logger = system.util.getLogger(</span><span style="color: #CE9178">&apos;Test Function&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  myFunction(inputA,inputB,inputC)</span></span>
<span class="line"><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Exception</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> e:</span></span>
<span class="line"><span style="color: #D4D4D4">  logger.error(traceback.format_exc(e))</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Logging</h3>



<p class="wp-block-paragraph">In addition to displaying the exception to users, exceptions should also be logged to the gateway to maintain a record of such events. Without logging, a user can close the exception pop-up, and all information associated with the event will be lost.</p>



<p class="wp-block-paragraph">Logging with <code>traceback.format_exc(e)</code> creates a well-formatted message with error type, message, and traceback, giving engineers the information they need to debug issues effectively.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from traceback import format_exc

try:
    1/0
except Exception as e:
    print type(e).__name__
    print ''
    print e.message
    print ''
    print format_exc(e)
    
>>> 
ZeroDivisionError

integer division or modulo by zero

Traceback (most recent call last):
  File "&lt;input>", line 4, in &lt;module>
ZeroDivisionError: integer division or modulo by zero

>>> </textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> traceback </span><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> format_exc</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">/</span><span style="color: #B5CEA8">0</span></span>
<span class="line"><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Exception</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> e:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">type</span><span style="color: #D4D4D4">(e).</span><span style="color: #9CDCFE">__name__</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;&apos;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4"> e.message</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&apos;&apos;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4"> format_exc(e)</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">&gt;&gt;&gt; </span></span>
<span class="line"><span style="color: #4EC9B0">ZeroDivisionError</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">integer division </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> modulo by zero</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">Traceback (most recent call last):</span></span>
<span class="line"><span style="color: #D4D4D4">  File </span><span style="color: #CE9178">&quot;&lt;input&gt;&quot;</span><span style="color: #D4D4D4">, line </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> &lt;module&gt;</span></span>
<span class="line"><span style="color: #4EC9B0">ZeroDivisionError</span><span style="color: #D4D4D4">: integer division </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> modulo by zero</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&gt;&gt;&gt; </span></span></code></pre></div>



<h2 class="wp-block-heading">Other Exceptions</h2>



<p class="wp-block-paragraph">You can raise your own Exceptions to catch errors that might not violate Python syntax by themselves. This is useful for sanitizing inputs or generally checking statuses before they cause errors later in program execution. You can also reraise within an Except block to add more context to an error message.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def divideNumbers(dividend, divisor):
  if divisor == 0:
    raise ValueError('Cannot divide by 0')
    
  try:
    output = dividend / divisor
  except Exception as e:
    raise Exception('Division error: {}'.format(e.message))
    
  return output</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">divideNumbers</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">dividend</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">divisor</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> divisor == </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">raise</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ValueError</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;Cannot divide by 0&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    output = dividend / divisor</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Exception</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> e:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">raise</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Exception</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;Division error: </span><span style="color: #569CD6">{}</span><span style="color: #CE9178">&apos;</span><span style="color: #D4D4D4">.format(e.message))</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> output</span></span></code></pre></div>



<h3 class="wp-block-heading">SQL Exceptions</h3>



<p class="wp-block-paragraph">When considering SQL exceptions, we first want to examine the query method. Where possible, we want to use named queries instead of prep queries because named queries provide much better error messages.</p>



<h3 class="wp-block-heading">Custom Exception Classes</h3>



<p class="wp-block-paragraph">Creating custom exception classes is incredibly easy to accomplish in Python. You might want to create separate exception types for user input errors and system errors.</p>



<h2 class="wp-block-heading" id="h-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">By moving beyond basic <code>try/except</code> usage and adopting a more structured approach, like catching specific exception types, handling both Python and Java errors in Ignition, and logging details, you can turn unexpected errors into actionable insights.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)">At DMC, we always apply these best practices across our automation and software projects to deliver systems that are robust, user-friendly, and scalable. Whether you’re building a new Ignition application or improving existing systems, stronger exception handling helps ensure greater dependability and performance.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Kicking off an automation project? DMC can help you take the next step!</strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Discover more about <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">Ignition solutions</a> and <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">HMI Programming services</a> with DMC and contact an expert today.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/44984/ignition-exception-handling/">Ignition Tricks: Improving Exception Handling and Error Logging</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Triggering Gateway File Syncs for Ignition 8.3 Using Git Hooks</title>
		<link>https://static.dmcinfo.com/blog/44721/ignition-8-3-gateway-file-sync-git/</link>
		
		<dc:creator><![CDATA[Wenjing Deng]]></dc:creator>
		<pubDate>Wed, 03 Jun 2026 23:00:00 +0000</pubDate>
				<category><![CDATA[HMI and SCADA]]></category>
		<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[GIT]]></category>
		<category><![CDATA[SCADA]]></category>
		<category><![CDATA[Workflows]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=44721</guid>

					<description><![CDATA[<p>Ignition 8.3’s file-based project structure makes it much easier to use standard Git workflows with SCADA projects. Project resources can now be version-controlled directly as files, which makes branch switching, pull requests, and external editing more practical. This also enables patterns&#160;such as&#160;using symbolic links to share project resources across environments. One issue that arises with [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/44721/ignition-8-3-gateway-file-sync-git/">Triggering Gateway File Syncs for Ignition 8.3 Using Git Hooks</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Ignition 8.3’s file-based project structure makes it much easier to use standard Git workflows with SCADA projects. Project resources can now be version-controlled directly as files, which makes branch switching, pull requests, and external editing more practical. This also enables patterns&nbsp;such as&nbsp;<a href="https://static.dmcinfo.com/blog/44390/symbolic-links-shared-ignition-project-libraries/">using symbolic links</a> to share project resources across environments.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--30)">One issue that arises with this workflow is that Ignition does not always immediately detect file changes made outside the Designer. After checking out a branch, merging changes, or pulling updates, the gateway will still need a manual file scan from the Gateway before the latest project or configuration files are reflected.</p>



<p class="wp-block-paragraph">To make development workflows smoother for our projects at DMC, we created a script that uses the Ignition 8.3 Gateway API endpoints to trigger project and configuration file scans. By integrating this script into Git hooks, file scans can run automatically after branch checkouts or merges, eliminating the need to manually navigate to the Gateway webpage and trigger them each time (fig1 and fig2). Additionally, developers can manually run the script from Bash or the command line to trigger file scans on demand.</p>



<p class="wp-block-paragraph">In this blog, we have provided a sample script and .env file, and we will walk you through the steps to set this up.</p>



<figure class="wp-block-image aligncenter size-full has-custom-border"><img decoding="async" width="1429" height="277" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-1.png" alt="Screenshot of the &quot;Platform Overview&quot; page in the Ignition Gateway UI." class="has-border-color has-custom-light-blue-border-color wp-image-44728" style="border-width:2px;border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-1.png 1429w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-1-300x58.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-1-1024x198.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-1-768x149.png 768w" sizes="(max-width: 1429px) 100vw, 1429px" /><figcaption class="wp-element-caption"><em>Figure 1: Platform File System Scan Button</em></figcaption></figure>



<figure class="wp-block-image aligncenter size-full has-custom-border"><img decoding="async" width="1427" height="334" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-2.png" alt="Screenshot of the Projects section of Ignition." class="has-border-color has-custom-light-blue-border-color wp-image-44729" style="border-width:2px;border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-2.png 1427w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-2-300x70.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-2-1024x240.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-2-768x180.png 768w" sizes="(max-width: 1427px) 100vw, 1427px" /><figcaption class="wp-element-caption"><em>Figure 2: Project File System Scan Button</em></figcaption></figure>



<h2 id="h-why-this-step-matters" class="wp-block-heading">Why This Step Matters</h2>



<p class="wp-block-paragraph">There are a variety of reasons why automating this step is both important and beneficial. This automation reduces friction in the development workflow, reducing some of the common sources of errors and delays while improving team-wide consistency and clarity. By using Git hooks to automate file syncing in Ignition, developers avoid repeated trips to the Gateway UI and reduce mental load.</p>



<p class="wp-block-paragraph">By adding automated file scans into the development workflow, teams can make Ignition 8.3 development feel more like regular software development, where Git-based practices like branching, merging, and pull requests fit naturally into SCADA projects.</p>



<h2 id="h-set-up-gateway-api-key" class="wp-block-heading">Set Up Gateway API Key</h2>



<p class="wp-block-paragraph">In order to access the API endpoint, we need to set up an API key in the Gateway. Follow <a href="https://www.docs.inductiveautomation.com/docs/8.3/platform/security/api-keys" target="_blank" rel="noreferrer noopener">Ignition’s manual</a> for this.</p>



<p class="wp-block-paragraph">By default, Ignition requires API keys to be used over secure HTTPS connections. Since this script commonly runs against local development Gateways using standard HTTP, the Require secure connections for API Keys setting must be disabled for the requests to succeed.</p>



<p class="wp-block-paragraph">Make sure to copy the ENTIRE api key. We will add it to the <em><strong>.env</strong></em> file in the next section.</p>



<h2 id="h-repo-and-environment-variables-set-up" class="wp-block-heading">Repo and Environment Variables Set Up</h2>



<p class="wp-block-paragraph">Copy the example script (included in the section below) into your desired location in your repo. For example, in this repo, we have put it at the following location and called it <strong>gateway_scan.py</strong>.</p>



<p class="wp-block-paragraph">Path: <em><strong>ignition-docker-8-3\scripts\gateway_scan</strong></em></p>



<figure class="wp-block-image size-full has-custom-border"><img decoding="async" width="1798" height="453" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-4.png" alt="Screenshot of a file explorer window displaying a Python source file named gateway_scan.py." class="wp-image-44730" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-4.png 1798w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-4-300x76.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-4-1024x258.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-4-768x193.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3.-git-workflow-image-4-1536x387.png 1536w" sizes="(max-width: 1798px) 100vw, 1798px" /></figure>



<p class="wp-block-paragraph">Next, add the following variables to your .env file:</p>



<p class="wp-block-paragraph"><strong><em>GATEWAY_IP= (your gateway’s IP address)</em><br><em>HTTP_PORT = (your gateway’s port)</em><br><em>GATEWAY_API_TOKEN=(your generated API token for the gateway)</em></strong></p>



<p class="wp-block-paragraph">The example script looks for these variables; if they are already in your <strong>.env</strong> and are named differently, open the example script and do a find-and-replace to update the variable names.</p>



<h2 id="h-git-hook-set-up" class="wp-block-heading">Git Hook Set Up</h2>



<p class="wp-block-paragraph">Git hooks let us automatically run scripts when certain Git actions occur. For this workflow, we typically set up Git hooks to run the gateway_scan.py script after branch checkouts and merges.</p>



<p class="wp-block-paragraph">This means that when a developer switches branches, pulls changes, or merges updates, the Gateway file scan can run automatically without having to open the Gateway webpage and manually trigger it.</p>



<p class="wp-block-paragraph">To set this up, create two files in the <strong>.git/hooks</strong> folder:</p>



<p class="wp-block-paragraph"><em><strong>.git/hooks/post-checkout<br>.git/hooks/post-merge</strong></em></p>



<p class="wp-block-paragraph">Paste the following code into both files:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#!/bin/sh

# Move to the root of the git repository
cd "$(git rev-parse --show-toplevel)" || exit 1

# Run file scan script
py scripts/gateway_scan/gateway_scan.py</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">#!/bin/sh</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"># Move to the root of the git repository</span></span>
<span class="line"><span style="color: #D4D4D4">cd </span><span style="color: #CE9178">&quot;$(git rev-parse --show-toplevel)&quot;</span><span style="color: #D4D4D4"> || exit </span><span style="color: #B5CEA8">1</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"># Run file scan script</span></span>
<span class="line"><span style="color: #D4D4D4">py scripts/gateway_scan/gateway_scan.py</span></span></code></pre></div>



<p class="wp-block-paragraph">The post-checkout hook runs after switching branches. The post-merge hook runs after a merge, which also commonly happens when pulling new changes from the remote repository.</p>



<p class="wp-block-paragraph">The first command moves the terminal to the root of the Git repository. This helps ensure the script runs from the correct location, even if Git triggers the hook from within the repository.</p>



<p class="wp-block-paragraph">The second command runs the Gateway scan script:</p>



<p class="wp-block-paragraph"><em><strong>py scripts/gateway_scan/gateway_scan.py</strong></em></p>



<p class="wp-block-paragraph">Developers can also run this command manually from Bash or the command line whenever they want to trigger a Gateway file scan on demand.</p>



<p class="wp-block-paragraph">If the repository contains multiple gateways you want to automatically file scan for, add a separate set of environment variables for each gateway in the <strong>.env file</strong>, create an API key for each gateway, and then update the <strong>gateway_scan.py</strong> script following the comments, so the script knows which gateways to scan.</p>



<h2 id="h-example-script-amp-env-file" class="wp-block-heading">Example Script &amp; env. File</h2>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#------------------Gateway Scan Trigger Script Example------------------
"""
Run script to trigger file scans for gateways.
"""
import os
from pathlib import Path
from urllib import error, request

REQUEST_TIMEOUT_SECONDS = 5

print("Syncing Ignition Gateway...", flush=True)


def load_env_file(env_path):
	"""
	Load simple KEY=value pairs from a .env file without third-party dependencies.
	"""
	if not env_path.exists():
		return

	for line in env_path.read_text(encoding="utf-8").splitlines():
		line = line.strip()

		if not line or line.startswith("#") or "=" not in line:
			continue

		key, value = line.split("=", 1)
		os.environ.setdefault(key.strip(), value.strip().strip("\"'"))


# Read in .env file
load_env_file(Path(__file__).resolve().parents&#91;2&#93; / ".env")

# Grab environment variables
# TODO: VERIFY YOUR .ENV FILE HAS THESE VARIABLES SET CORRECTLY
# CREATE ADDITIONAL ENVIRONMENT VARIABLES FOR ADDITIONAL GATEWAYS IF NEEDED
# BY COPYING THE FOLLOWING FORMAT
GATEWAY_PORT = os.getenv("HTTP_PORT_IGN")
GATEWAY_IP = os.getenv("GATEWAY_IP")
GATEWAY_API_TOKEN = os.getenv("GATEWAY_API_TOKEN")

# TODO: ADD ADDITIONAL GATEWAYS HERE IF NEEDED!
gateways = {
	"Ignition": {"ip": GATEWAY_IP, "port": GATEWAY_PORT, "token": GATEWAY_API_TOKEN}
	# Additional gateways can be added here in the same format
}

actions = &#91;"projects", "config"&#93;

def post_scan_request(url, headers):
	"""
	Post a gateway scan request and return the HTTP status code.
	"""
	req = request.Request(url, headers=headers, method="POST")

	with request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as response:
		return response.status


def trigger_scans():
	"""
	Trigger scans on the specified gateways.
	"""
	for name, config in gateways.items():
		ip = config&#91;"ip"&#93;
		token = config&#91;"token"&#93;
		port = config&#91;"port"&#93;

		if not ip or not token or not port:
			var_name = "ip address" if not ip else "API token" if not token else "Port"
			print(f"Skipping {name}: Missing environment variable '{var_name}'.")
			continue

		headers = {
			"X-Ignition-API-Token": f"{token}"
		}

		for action in actions:
			# Ignition uses the final path segment to choose the scan type
			url = f""

			try:
				status_code = post_scan_request(url, headers)

				if status_code == 200:
					print(f"Success: File Scan {name} {action}")
				else:
					print(f"Failed: File Scan {name} {action} (Status: {status_code})")
			except TimeoutError:
				print(f"Timeout: {name} took too long to respond.")
			except error.HTTPError as err:
				print(f"Failed: File Scan {name} {action} (Status: {err.code})")
			except error.URLError as err:
				print(f"Connection Error: Could not reach {name} at {ip}. ({err.reason})")


if __name__ == "__main__":
	trigger_scans()

# ---------------------.env file example for one gateway--------------------
# HTTP_PORT_IGN= "your gateway's port"
# GATEWAY_IP= "your gateway's IP address"
# GATEWAY_API_TOKEN= "your gateway's API token"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#------------------Gateway Scan Trigger Script Example------------------</span></span>
<span class="line"><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">Run script to trigger file scans for gateways.</span></span>
<span class="line"><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> os</span></span>
<span class="line"><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> pathlib </span><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> Path</span></span>
<span class="line"><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> urllib </span><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> error, request</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">REQUEST_TIMEOUT_SECONDS = </span><span style="color: #B5CEA8">5</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Syncing Ignition Gateway...&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">flush</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">True</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">load_env_file</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">env_path</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">	Load simple KEY=value pairs from a .env file without third-party dependencies.</span></span>
<span class="line"><span style="color: #CE9178">	&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> env_path.exists():</span></span>
<span class="line"><span style="color: #D4D4D4">		</span><span style="color: #C586C0">return</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> line </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> env_path.read_text(</span><span style="color: #9CDCFE">encoding</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;utf-8&quot;</span><span style="color: #D4D4D4">).splitlines():</span></span>
<span class="line"><span style="color: #D4D4D4">		line = line.strip()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">		</span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> line </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> line.startswith(</span><span style="color: #CE9178">&quot;#&quot;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;=&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> line:</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #C586C0">continue</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">		key, value = line.split(</span><span style="color: #CE9178">&quot;=&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">		os.environ.setdefault(key.strip(), value.strip().strip(</span><span style="color: #CE9178">&quot;</span><span style="color: #D7BA7D">\&quot;</span><span style="color: #CE9178">&apos;&quot;</span><span style="color: #D4D4D4">))</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Read in .env file</span></span>
<span class="line"><span style="color: #D4D4D4">load_env_file(Path(</span><span style="color: #9CDCFE">__file__</span><span style="color: #D4D4D4">).resolve().parents&#91;</span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">&#93; / </span><span style="color: #CE9178">&quot;.env&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Grab environment variables</span></span>
<span class="line"><span style="color: #6A9955"># </span><span style="color: #569CD6">TODO</span><span style="color: #6A9955">: VERIFY YOUR .ENV FILE HAS THESE VARIABLES SET CORRECTLY</span></span>
<span class="line"><span style="color: #6A9955"># CREATE ADDITIONAL ENVIRONMENT VARIABLES FOR ADDITIONAL GATEWAYS IF NEEDED</span></span>
<span class="line"><span style="color: #6A9955"># BY COPYING THE FOLLOWING FORMAT</span></span>
<span class="line"><span style="color: #D4D4D4">GATEWAY_PORT = os.getenv(</span><span style="color: #CE9178">&quot;HTTP_PORT_IGN&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">GATEWAY_IP = os.getenv(</span><span style="color: #CE9178">&quot;GATEWAY_IP&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">GATEWAY_API_TOKEN = os.getenv(</span><span style="color: #CE9178">&quot;GATEWAY_API_TOKEN&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># </span><span style="color: #569CD6">TODO</span><span style="color: #6A9955">: ADD ADDITIONAL GATEWAYS HERE IF NEEDED!</span></span>
<span class="line"><span style="color: #D4D4D4">gateways = {</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #CE9178">&quot;Ignition&quot;</span><span style="color: #D4D4D4">: {</span><span style="color: #CE9178">&quot;ip&quot;</span><span style="color: #D4D4D4">: GATEWAY_IP, </span><span style="color: #CE9178">&quot;port&quot;</span><span style="color: #D4D4D4">: GATEWAY_PORT, </span><span style="color: #CE9178">&quot;token&quot;</span><span style="color: #D4D4D4">: GATEWAY_API_TOKEN}</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #6A9955"># Additional gateways can be added here in the same format</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">actions = &#91;</span><span style="color: #CE9178">&quot;projects&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;config&quot;</span><span style="color: #D4D4D4">&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">post_scan_request</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">url</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">headers</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">	Post a gateway scan request and return the HTTP status code.</span></span>
<span class="line"><span style="color: #CE9178">	&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">	req = request.Request(url, </span><span style="color: #9CDCFE">headers</span><span style="color: #D4D4D4">=headers, </span><span style="color: #9CDCFE">method</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;POST&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #C586C0">with</span><span style="color: #D4D4D4"> request.urlopen(req, </span><span style="color: #9CDCFE">timeout</span><span style="color: #D4D4D4">=REQUEST_TIMEOUT_SECONDS) </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> response:</span></span>
<span class="line"><span style="color: #D4D4D4">		</span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> response.status</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">trigger_scans</span><span style="color: #D4D4D4">():</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #CE9178">&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #CE9178">	Trigger scans on the specified gateways.</span></span>
<span class="line"><span style="color: #CE9178">	&quot;&quot;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> name, config </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> gateways.items():</span></span>
<span class="line"><span style="color: #D4D4D4">		ip = config&#91;</span><span style="color: #CE9178">&quot;ip&quot;</span><span style="color: #D4D4D4">&#93;</span></span>
<span class="line"><span style="color: #D4D4D4">		token = config&#91;</span><span style="color: #CE9178">&quot;token&quot;</span><span style="color: #D4D4D4">&#93;</span></span>
<span class="line"><span style="color: #D4D4D4">		port = config&#91;</span><span style="color: #CE9178">&quot;port&quot;</span><span style="color: #D4D4D4">&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">		</span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> ip </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> token </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> port:</span></span>
<span class="line"><span style="color: #D4D4D4">			var_name = </span><span style="color: #CE9178">&quot;ip address&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> ip </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;API token&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> token </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Port&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;Skipping </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">name</span><span style="color: #569CD6">}</span><span style="color: #CE9178">: Missing environment variable &apos;</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">var_name</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&apos;.&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #C586C0">continue</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">		headers = {</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #CE9178">&quot;X-Ignition-API-Token&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">token</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">		}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">		</span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> action </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> actions:</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #6A9955"># Ignition uses the final path segment to choose the scan type</span></span>
<span class="line"><span style="color: #D4D4D4">			url = </span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;http://</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">ip</span><span style="color: #569CD6">}</span><span style="color: #CE9178">:</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">port</span><span style="color: #569CD6">}</span><span style="color: #CE9178">/data/api/v1/scan/</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">action</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">				status_code = post_scan_request(url, headers)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">				</span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> status_code == </span><span style="color: #B5CEA8">200</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">					</span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;Success: File Scan </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">name</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">action</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">				</span><span style="color: #C586C0">else</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">					</span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;Failed: File Scan </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">name</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">action</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (Status: </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">status_code</span><span style="color: #569CD6">}</span><span style="color: #CE9178">)&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">TimeoutError</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">				</span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;Timeout: </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">name</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> took too long to respond.&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> error.HTTPError </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> err:</span></span>
<span class="line"><span style="color: #D4D4D4">				</span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;Failed: File Scan </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">name</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">action</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> (Status: </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">err.code</span><span style="color: #569CD6">}</span><span style="color: #CE9178">)&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">			</span><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> error.URLError </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> err:</span></span>
<span class="line"><span style="color: #D4D4D4">				</span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">f</span><span style="color: #CE9178">&quot;Connection Error: Could not reach </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">name</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> at </span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">ip</span><span style="color: #569CD6">}</span><span style="color: #CE9178">. (</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">err.reason</span><span style="color: #569CD6">}</span><span style="color: #CE9178">)&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">__name__</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&quot;__main__&quot;</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">	trigger_scans()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># ---------------------.env file example for one gateway--------------------</span></span>
<span class="line"><span style="color: #6A9955"># HTTP_PORT_IGN= &quot;your gateway&apos;s port&quot;</span></span>
<span class="line"><span style="color: #6A9955"># GATEWAY_IP= &quot;your gateway&apos;s IP address&quot;</span></span>
<span class="line"><span style="color: #6A9955"># GATEWAY_API_TOKEN= &quot;your gateway&apos;s API token&quot;</span></span></code></pre></div>



<h2 id="h-conclusion" class="wp-block-heading" style="padding-top:var(--wp--preset--spacing--40)">Conclusion</h2>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--40)">Automating file syncs in Ignition 8.3 is a simple configuration change that can deliver meaningful improvements to your development workflow. By reducing manual steps and ensuring the Gateway always reflects the latest project state, teams can work more efficiently and with greater confidence. For engineers using Git to manage their Ignition projects, this approach unlocks the full benefits of modern version control while keeping SCADA development reliable and consistent.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Starting an Ignition project? DMC can help you take the next step.</strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Find out more about our <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/" target="_blank" rel="noreferrer noopener">Manufacturing Automation</a> and <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/" target="_blank" rel="noreferrer noopener">SCADA programming</a> solutions and reach out to an expert today.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/44721/ignition-8-3-gateway-file-sync-git/">Triggering Gateway File Syncs for Ignition 8.3 Using Git Hooks</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Setting Up Symbolic Links for Shared Project Libraries Across Ignition 8.3 Gateways</title>
		<link>https://static.dmcinfo.com/blog/44390/symbolic-links-shared-ignition-project-libraries/</link>
		
		<dc:creator><![CDATA[Wenjing Deng]]></dc:creator>
		<pubDate>Fri, 15 May 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[GIT]]></category>
		<category><![CDATA[ignition]]></category>
		<category><![CDATA[Libraries]]></category>
		<category><![CDATA[Workflows]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=44390</guid>

					<description><![CDATA[<p>Ignition 8.3’s file-based project structure makes it practical to treat gateway resources as standard source-controlled assets, allowing teams to track changes in Git, review diffs, and modify certain files directly outside of the Designer when needed. This level of transparency and control significantly improves the development workflow. In a recent Ignition 8.3 project, we had [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/44390/symbolic-links-shared-ignition-project-libraries/">Setting Up Symbolic Links for Shared Project Libraries Across Ignition 8.3 Gateways</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Ignition 8.3’s file-based project structure makes it practical to treat gateway resources as standard source-controlled assets, allowing teams to track changes in Git, review diffs, and modify certain files directly outside of the Designer when needed. This level of transparency and control significantly improves the development workflow.</p>



<p class="wp-block-paragraph">In a recent Ignition 8.3 project, we had two gateways in a single Git repository that needed to share library elements. While 8.3 enables a more Git-centric workflow, it does not provide a built-in mechanism to keep shared resources synchronized across multiple gateways. Without an automatic way to manage this, shared libraries can quickly drift and become difficult to maintain.</p>



<p class="wp-block-paragraph">We addressed this by creating symbolic links from each gateway’s library folders to a shared “source of truth” directory. A <strong>symbolic link</strong> (symlink) is a special file that points to another file or folder—like a shortcut at the filesystem level. When you access it, the system transparently redirects you to the target location. This approach allows both gateways to reference the same underlying files while still fitting cleanly into a Git-based workflow, making it a simple, low-friction way to keep shared resources consistent.</p>



<p class="wp-block-paragraph">This blog walks through how to set up shared libraries between two Ignition gateways in a single Git repository using symlinks on Windows, helping you avoid duplication and keep shared code synchronized in one place.</p>



<p class="wp-block-paragraph">With this setup, any time a symlinked file is modified in a Designer and saved, it’s immediately overwritten in the shared “source of truth” location. After changes are made and tested in one gateway project’s Designer, the files can be committed and pushed to the repo as usual.</p>



<p class="wp-block-paragraph">We’ll walk through setting up a shared script library folder as an example. You can use the same pattern to share views, styles, and additional files as needed for your project.</p>



<h2 class="wp-block-heading" id="h-what-are-symbolic-links">What are Symbolic Links?</h2>



<p class="wp-block-paragraph">A symbolic link, often referred to as a <strong>symlink</strong>, is a reference point in a filesystem that points one file or folder to another location. Instead of duplicating the files, a symlink acts as a pointer. When an application accesses the symlinked path, the operating system (OS) redirects it to the target destination.</p>



<p class="wp-block-paragraph">In Ignition 8.3, a symlinked folder behaves exactly like a project directory. Associated scripts, views, and resources load as one would expect; however, the actual files live somewhere else in the filesystem.</p>



<h2 class="wp-block-heading" id="h-sample-repository-structure">Sample Repository Structure</h2>



<p class="wp-block-paragraph">Here is a visual representation of what the structure would look like after the symlinks are set up. The file structure for <strong>gateway1</strong> and <strong>gateway2</strong> down to script-python is default to ignition. You will have to create the “shared” folder location and structure manually in your repo, and you can organize it anyway you want.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)"><strong>repo/<br>└── gateways/<br>&nbsp; &nbsp;├── shared/<br>&nbsp; &nbsp;│ &nbsp; └── script-python/<br>&nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; └── library/ (real files live here for this example)<br>&nbsp; &nbsp;│<br>&nbsp; &nbsp;├── gateway1/<br>&nbsp; &nbsp;│ &nbsp; └── projects/<br>&nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; └── project1/<br>&nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── ignition/<br>&nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── script-python/<br>&nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── library/ -&gt; symlink to ../../../../../shared/script-python/library<br>&nbsp; &nbsp;│<br>&nbsp; &nbsp;└── gateway2/<br>&nbsp; &nbsp; &nbsp; &nbsp;└── projects/<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;└── project2/<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;└── ignition/<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;└── script-python/<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;└── library/ -&gt; symlink to ../../../../../shared/script-python/library</strong></p>



<h2 class="wp-block-heading" id="h-setup-steps-for-windows">Setup Steps for Windows</h2>



<p class="wp-block-paragraph">Before creating any symbolic links, complete the following one-time setup steps. <strong>Every developer working with this repository must perform these steps on their local machine</strong>. Skipping them can result in broken links when the repo is cloned or checked out.</p>



<h3 class="wp-block-heading" id="h-prerequisites">Prerequisites</h3>



<p class="wp-block-paragraph"><strong>1. Enable Git symlink support</strong></p>



<p class="wp-block-paragraph">By default, Git on Windows may treat symlinks as plain text files. This setting ensures symlinks are created and checked out correctly.</p>



<p class="wp-block-paragraph">Run the following command in <strong>Git Bash</strong>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>git config --global core.symlinks true</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">git config --global core.symlinks </span><span style="color: #569CD6">true</span></span></code></pre></div>



<figure class="wp-block-image aligncenter size-full has-custom-border"><img decoding="async" width="1082" height="209" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-1.png" alt="Open command window with Git command to enable the use of symbolic links across all repositories on a machine." class="wp-image-44460" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-1.png 1082w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-1-300x58.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-1-1024x198.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-1-768x148.png 768w" sizes="(max-width: 1082px) 100vw, 1082px" /></figure>



<p class="wp-block-paragraph"><strong>2. Enable Windows Developer Mode</strong></p>



<p class="wp-block-paragraph">Developer Mode<strong> </strong>allows non-admin users to create symbolic links without permission-related issues.</p>



<p class="wp-block-paragraph"><strong>Settings &gt; Privacy &amp; Security &gt; For Developers &gt; Developer Mode</strong></p>



<p class="wp-block-paragraph">Turn Developer Mode <strong>on</strong>.</p>



<p class="wp-block-paragraph"><strong>3. Restart your computer</strong></p>



<p class="wp-block-paragraph">Restarting your computer ensures Developer Mode is fully applied before creating symlinks.</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="624" height="387" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-2.png" alt="Advanced system settings in Windows, specifically highlighting options for developers and terminal management." class="wp-image-44414" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;aspect-ratio:1.6124476361460203;width:624px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-2.png 624w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-2-300x186.png 300w" sizes="(max-width: 624px) 100vw, 624px" /></figure>



<h2 class="wp-block-heading" id="h-initial-creation-of-symbolic-links">Initial Creation of Symbolic Links</h2>



<p class="wp-block-paragraph">Follow the steps below to set up the initial symlinks for the <code>script-python</code> library folder in our example. The same approach can be used for other shared resources.</p>



<h3 class="wp-block-heading" id="h-gateway-1"><strong>Gateway 1:</strong></h3>



<p class="wp-block-paragraph"><strong>1. Open Command Prompt as an Administrator</strong></p>



<p class="wp-block-paragraph"><strong>2. Navigate to the target directory for your symbolic links</strong></p>



<p class="wp-block-paragraph" style="padding-top:0;padding-bottom:var(--wp--preset--spacing--40)">Move to the directory where the symlink will live in <strong>Gateway 1</strong>: <em><strong>cd gateways\gateway1\projects\project1\ignition\script-python</strong></em></p>



<figure class="wp-block-image aligncenter size-large is-resized has-custom-border" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--60)"><img decoding="async" width="1024" height="129" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-3-1024x129.png" alt="Administrator: Command Prompt window active in a specific directory path." class="wp-image-44417" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;aspect-ratio:7.9392168322618355;object-fit:cover;width:691px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-3-1024x129.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-3-300x38.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-3-768x97.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-3.png 1444w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph" style="padding-top:0;padding-bottom:var(--wp--preset--spacing--40)"><strong>3. Move any existing library files:</strong></p>



<p class="wp-block-paragraph" style="padding-top:0;padding-bottom:var(--wp--preset--spacing--40)">If you already have files in the library folder and/or the library folder exists, move the entire library folder to the shared directory<span style="box-sizing: border-box; margin: 0px; padding: 0px;">&nbsp;at&nbsp;<em><strong>gateways/shared/script-python</strong></em></span>. If not, skip this step.</p>



<p class="wp-block-paragraph" style="padding-top:0;padding-bottom:var(--wp--preset--spacing--40)">If you leave the library folder here: <em><strong>\gateways\gateway1\projects\project1\ignition\script-python</strong>. </em>The following error will occur because Windows cannot create a link where a directory already exists:</p>



<figure class="wp-block-image aligncenter size-full has-custom-border" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--60)"><img decoding="async" width="2306" height="161" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-4.png" alt="The error message &quot;Cannot create a file when that file already exists&quot; indicates that a symbolic link or file named library already exists in the destination directory." class="wp-image-44419" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;aspect-ratio:14.424507658643327" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-4.png 2306w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-4-300x21.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-4-1024x71.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-4-768x54.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-4-1536x107.png 1536w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-4-2048x143.png 2048w" sizes="(max-width: 2306px) 100vw, 2306px" /></figure>



<p class="wp-block-paragraph" style="padding-top:0;padding-bottom:var(--wp--preset--spacing--40)"><strong>4. Create the symbolic link</strong></p>



<p class="wp-block-paragraph" style="padding-top:0;padding-bottom:0">Run the command below to create the symlink linked to the actual files in the shared location:</p>



<p class="wp-block-paragraph"><em><strong>mklink /D library &#8230;&#8230;&#8230;.\shared\script-python\library</strong></em></p>



<figure class="wp-block-image aligncenter size-full has-custom-border" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--60)"><img decoding="async" width="2325" height="293" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-5.png" alt="GIT command used to successfully create a symbolic link to a folder." class="wp-image-44421" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-5.png 2325w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-5-300x38.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-5-1024x129.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-5-768x97.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-5-1536x194.png 1536w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-5-2048x258.png 2048w" sizes="(max-width: 2325px) 100vw, 2325px" /></figure>



<p class="wp-block-paragraph"><strong>5. Verify the symlink was created successfully</strong></p>



<p class="wp-block-paragraph">Verify the link has been created by running the command <em>dir</em> at the symlink location in the command prompt. If the symlink was created correctly, then you should see it in your output.</p>



<figure class="wp-block-image aligncenter size-full has-custom-border" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--60)"><img decoding="async" width="1950" height="499" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-6-1-e1778267616906.png" alt="A [dir] command output shows a directory listing in a Windows Command Prompt, highlighting a symbolic link." class="wp-image-44422" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-6-1-e1778267616906.png 1950w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-6-1-e1778267616906-300x77.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-6-1-e1778267616906-1024x262.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-6-1-e1778267616906-768x197.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-6-1-e1778267616906-1536x393.png 1536w" sizes="(max-width: 1950px) 100vw, 1950px" /></figure>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--40)">In addition, you can visually verify that the folder was created correctly in File Explorer by looking for the arrow icon in the bottom left. When you double-click into this symlinked folder, it will take you to the location it is linked to.</p>



<figure class="wp-block-image aligncenter size-full has-custom-border" style="margin-top:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--60)"><img decoding="async" width="650" height="271" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/Picture12.png" alt="Windows 11 File Explorer window for a directory named script-python." class="wp-image-44431" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/Picture12.png 650w, https://static.dmcinfo.com/wp-content/uploads/2026/05/Picture12-300x125.png 300w" sizes="(max-width: 650px) 100vw, 650px" /></figure>



<h3 class="wp-block-heading" id="h-gateway-2">Gateway 2</h3>



<p class="wp-block-paragraph">Repeat the same steps for <strong>Gateway 2</strong>, adjusting the path as needed:</p>



<p class="wp-block-paragraph"><em><strong>cd gateways\gateway2\projects\project2\ignition\script-python</strong></em></p>



<p class="wp-block-paragraph">Create the symlink pointing to the same library location.</p>



<p class="wp-block-paragraph">Once both gateways are linked, the shared library folder is ready for use. Any changes made through one gateway’s <strong>Ignition Designer</strong> will be written directly to the shared directory and can be committed to Git as usual.</p>



<h2 class="wp-block-heading" id="h-ignition-designer-gateway-refresh-and-test">Ignition Designer/Gateway Refresh and Test</h2>



<p class="wp-block-paragraph">After creating the symbolic links, the final step is to confirm that Ignition detects and uses the shared files properly. Because Ignition doesn’t automatically reload filesystem changes, users must manually initiate file and project scans to update each gateway.</p>



<p class="wp-block-paragraph"><strong>1. Close all open Ignition Designer sessions</strong></p>



<p class="wp-block-paragraph">Closing active sessions of Designer resolves any potential validation interference caused by cached projects.</p>



<p class="wp-block-paragraph"><strong>2. Trigger file and project scans on both Gateways</strong></p>



<p class="wp-block-paragraph">On each gateway, run the following:</p>



<ul class="wp-block-list">
<li>Platform → Overview →<strong> Scan File System</strong></li>



<li>Platform → System → Projects → <strong>Scan Projects</strong></li>
</ul>



<p class="wp-block-paragraph"><strong>3. Open Ignition Designer for Gateway 1</strong></p>



<ul class="wp-block-list">
<li>Create a new script or modify an existing script in the share library.</li>



<li>Save the changes.</li>
</ul>



<p class="wp-block-paragraph"><strong>4. Refresh Gateway 2</strong></p>



<ul class="wp-block-list">
<li style="padding-bottom:var(--wp--preset--spacing--40)">From the <strong>Gateway 2</strong> web UI, trigger both the file system scan and project scan again.</li>
</ul>



<p class="wp-block-paragraph"><strong>5. Open Ignition Developer for Gateway 2</strong></p>



<ul class="wp-block-list">
<li style="padding-bottom:var(--wp--preset--spacing--40)">Open Ignition Developer for the second Gateway and verify that the adjustments are present.</li>
</ul>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="1124" height="218" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-8.png" alt="Platform File Scan button in Ignition 8.3" class="has-border-color has-custom-light-gray-neutral-2-border-color wp-image-44424" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;width:1200px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-8.png 1124w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-8-300x58.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-8-1024x199.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-8-768x149.png 768w" sizes="(max-width: 1124px) 100vw, 1124px" /><figcaption class="wp-element-caption">Platform File Scan Button</figcaption></figure>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="1128" height="265" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-9.png" alt="Project File Scan button in Ignition 8.3" class="has-border-color has-custom-light-gray-neutral-2-border-color wp-image-44426" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;width:1200px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-9.png 1128w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-9-300x70.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-9-1024x241.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/ignition-8.3-symlinks-image-9-768x180.png 768w" sizes="(max-width: 1128px) 100vw, 1128px" /><figcaption class="wp-element-caption">Project File Scan Button</figcaption></figure>



<p class="wp-block-paragraph">Now the library symlinks are set up and ready for use. If the changes appear as expected, the symbolic link configuration is working correctly, and both gateways are pulling from the same shared source of truth. Once validated, follow your project&#8217;s specific git workflow to push these changes to your repository.</p>



<h2 class="wp-block-heading" id="h-final-thoughts-and-best-practices">Final Thoughts and Best Practices</h2>



<p class="wp-block-paragraph">It&#8217;s important to keep in mind that whenever a file in the gateway filesystem is changed, the gateway doesn’t automatically update to reflect those changes. You will need to perform two file scans for the latest changes to be reflected. The screenshots below show where to trigger these scans.</p>



<p class="wp-block-paragraph">At some point during testing, you may need to view/test a library file in both gateways. In this scenario, it is important to regularly perform the above file and project scans, as changes are being made and saved. Below is an example of a possible order of operations:</p>



<ol class="wp-block-list">
<li>Make changes to library file in <strong>Gateway 1</strong> project designer.</li>



<li>Save changes to library file in <strong>Gateway 1</strong> project designer.</li>



<li>Open <strong>Gateway 2</strong> webpage UI.</li>



<li>Press <strong>Scan File System</strong> on both <strong>Platform</strong> <strong>&gt; Overview</strong> page and <strong>Platform &gt; System &gt; Projects</strong> page for <strong>Gateway 2</strong>.</li>



<li>Open a fresh designer session of <strong>Gateway 2’s</strong> project to view latest changes.</li>
</ol>



<p class="wp-block-paragraph">Keep in mind that if changes are made in both gateways to the same library object, the last place it was saved will be the effective, latest state of the file. In the above example, if a change is made in <strong>Gateway 2’s</strong> project designer session and saved there, <strong>Gateway 1</strong> would have stale library files internally, requiring file scans to refresh them.</p>



<p class="wp-block-paragraph">To avoid accidentally overwriting changes, the best practice is to separate work into separate commits and modify a given shared file from only one gateway at a time.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--40)">Finally, make sure the other developers run through the setup steps on their machines to avoid accidentally breaking any symbolic links during initial setup.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step">Planning your next automation project? DMC can help you take the next step.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Get expert <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/">Automation</a> engineering and <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">Ignition Programming</a> solutions from DMC. Talk with an Ignition expert today.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/44390/symbolic-links-shared-ignition-project-libraries/">Setting Up Symbolic Links for Shared Project Libraries Across Ignition 8.3 Gateways</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Ignition Perspective Tricks: Embedded Views in Tables Cells</title>
		<link>https://static.dmcinfo.com/blog/43002/ignition-perspective-embedded-views-tables-cells/</link>
		
		<dc:creator><![CDATA[Isabelle Chan]]></dc:creator>
		<pubDate>Thu, 23 Apr 2026 13:22:00 +0000</pubDate>
				<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=43002</guid>

					<description><![CDATA[<p>Ignition Perspective’s Table component offers great flexibility when designing powerful user interfaces, including the ability to display other views within table cells. In this article, we’ll cover how to configure a table cell to use an embedded view, allowing us to build screens that make it easier for users to understand and interact with the [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/43002/ignition-perspective-embedded-views-tables-cells/">Ignition Perspective Tricks: Embedded Views in Tables Cells</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Ignition Perspective’s Table component offers great flexibility when designing powerful user interfaces, including the ability to display other views within table cells. In this article, we’ll cover how to configure a table cell to use an embedded view, allowing us to build screens that make it easier for users to understand and interact with the data.</p>



<h2 id="h-the-example" class="wp-block-heading">The Example</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-0e47273b wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40%">
<p class="wp-block-paragraph">For this example, let us imagine there are simple weather stations across the country reporting the communication status, the type of weather (represented by an integer), and temperature. Each city is set up with User Defined Types (UDT) containing this information [Figure 1]. We will then use this information to build an interface to allow users to individually enable and disable weather stations and view their statuses.</p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="2100" height="866" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-1.jpg" alt="Ignition Perspective user defined types (UDT)" class="wp-image-43261" style="aspect-ratio:2.4250297715708564;width:643px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-1.jpg 2100w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-1-300x124.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-1-1024x422.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-1-768x317.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-1-1536x633.jpg 1536w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-1-2048x845.jpg 2048w" sizes="(max-width: 2100px) 100vw, 2100px" /><figcaption class="wp-element-caption"><em>Figure 1</em></figcaption></figure>
</div>
</div>



<h2 id="h-setting-up-the-table" class="wp-block-heading">Setting Up the Table</h2>



<p class="wp-block-paragraph">First, we will add a table to a Perspective screen and bind the table’s data property to the tags. To do this, we look through the Cities folder and parse the tag values into a JSON format [Figure 2].</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)">This method is preferred for its scalability, as new cities added to the tags will automatically appear on the screen. This results in a table with the raw tag data.</p>



<figure class="wp-block-image aligncenter size-large is-resized" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img decoding="async" width="1024" height="979" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-2-2-1024x979.jpg" alt="Ignition Perspective 'CITIES' folder in JSON format." class="wp-image-43257" style="width:730px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-2-2-1024x979.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-2-2-300x287.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-2-2-768x734.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-2-2.jpg 1082w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Figure 2</em></figcaption></figure>



<figure class="wp-block-image aligncenter size-large is-resized"><img decoding="async" width="1024" height="712" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-3-1024x712.jpg" alt="Weather Table" class="wp-image-43071" style="width:730px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-3-1024x712.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-3-300x208.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-3-768x534.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-3.jpg 1180w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Figure 3</em></figcaption></figure>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-0e47273b wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<h2 id="h-column-configuration" class="wp-block-heading" style="padding-top:var(--wp--preset--spacing--30)">Column Configuration</h2>



<p class="wp-block-paragraph">But how do we make the data easier for users to quickly understand? We can do that by enhancing the table by configuring the five columns to have the following display:</p>



<ol start="1" class="wp-block-list">
<li>City: the name of the city</li>



<li>Enabled: a toggle switch controlling if a weather station is enabled or disabled</li>



<li>CommsStatus: an icon indicating if a weather station is communicating properly</li>



<li>Temperature (F): the last reported temperature</li>



<li>Weather: an icon based on an enumeration</li>
</ol>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)">The end goal is to have a table that looks like this.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="1175" height="715" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5.png" alt="Configured weather table." class="wp-image-43276" style="width:1050px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5.png 1175w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5-300x183.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5-1024x623.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5-768x467.png 768w" sizes="(max-width: 1175px) 100vw, 1175px" /><figcaption class="wp-element-caption"><em>Figure 4</em></figcaption></figure>
</div>
</div>



<h3 id="h-background-knowledge-passing-data-into-an-embedded-view-in-a-table" class="wp-block-heading" style="padding-top:var(--wp--preset--spacing--40)">Background Knowledge: Passing Data into an Embedded View in a Table</h3>



<p class="wp-block-paragraph" id="h-before-discussing-the-detailed-process-for-configuring-each-column-let-s-first-explain-how-to-transfer-data-into-embedded-views-in-tables-as-this-understanding-is-crucial-for-our-example-to-start-the-perspective-table-component-has-a-set-of-properties-per-cell-the-full-list-is">Before discussing the detailed process for configuring each column, let&#8217;s first explain how to transfer data into embedded views in tables, as this understanding is crucial for our example. To start, the Perspective table component has a set of properties per cell. The full list is:</p>



<ul class="wp-block-list">
<li><code>:column</code> : the current column name</li>



<li><code><strong>columnIndex</strong></code>: index of the current column</li>



<li><code><strong>row</strong></code>: index of the current row</li>



<li><code><strong>rowData</strong></code>: table data for the current row in a JSON format</li>



<li><code><strong>rowIndex</strong></code>: the displayed index of the current row (if only a select number of rows are displayed at a given time)</li>



<li><code><strong>value</strong></code>: the value being passed into the cell</li>
</ul>



<p class="wp-block-paragraph">The table component also has a <code>columns</code> property, where for each column you can set the <code>viewPath</code> to be a path to another Perspective View. This is how you configure a view to be embedded in a table. Now the problem is, how do you pass information from your table into this embedded view?</p>



<p class="wp-block-paragraph">The answer is to set the embedded view&#8217;s parameters to match the names of the table properties. For example, if you want to pass in the name of the current column into your embedded view, you would add a parameter called <code>column</code> to your embedded view.</p>



<p class="wp-block-paragraph">You can also add custom properties under <code>columns.viewParams</code> to pass into the embedded view. Similar to the built-in Ignition cell properties above, once an input parameter with the same name as the new custom property is set up on the embedded view, that value will be passed in from the parent.</p>



<h3 id="h-column-enabled" class="wp-block-heading">Column: Enabled</h3>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--40)">Now that we have the background knowledge of how to pass information into an embedded View, let’s use that to configure the Enabled column. The first step will be to create a view called <strong>EnabledView</strong> that contains a toggle switch component and link the view path to the Enabled column’s <code><strong>viewPath</strong></code> property [Figure 5]. By adding an input param called <code><strong>value</strong></code> to <strong>EnabledView </strong>[Figure 6], the enabled status will be passed automatically into <strong>EnabledView</strong>.<a id="_msocom_1"></a></p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-0e47273b wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="438" height="561" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-5-3.jpg" alt="Enabled column's viewPath property." class="wp-image-43079" style="aspect-ratio:0.780751814403573;object-fit:contain;width:312px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-5-3.jpg 438w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-5-3-234x300.jpg 234w" sizes="(max-width: 438px) 100vw, 438px" /><figcaption class="wp-element-caption"><em>Figure </em>5</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full is-style-default"><img decoding="async" width="1634" height="830" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-gif-1.gif" alt="Enabling different parameters in weather table." class="wp-image-43137" style="aspect-ratio:1.968431730574153;object-fit:contain"/><figcaption class="wp-element-caption"><em>Figure </em>6</figcaption></figure>
</div>
</div>



<p class="wp-block-paragraph" style="padding-top:var(--wp--preset--spacing--30)">But how do you make sure the tag value is updated when the user presses the toggle button? There are a few different possible solutions for this:</p>



<p class="wp-block-paragraph"><strong>Option 1:</strong> Create a Message Handler to write to tags and refresh the table data. This is DMC’s recommended approach because it centralizes all tag reads in one place, which is more performant, especially for large datasets. It also ensures that the table data is always synchronous, which is necessary if the table has columns that rely on multiple tag values. For instance, in our example, the CommsStatus column relies on the Enabled column data. So when you update the Enabled column, you also want the CommsStatus column to update.</p>



<p class="wp-block-paragraph"><strong>Option 2: </strong>Pass in the tag path into the embedded view and do a bidirectional binding within the embedded view. While this approach may be more straightforward for smaller tables, it can negatively impact performance because tag reads occur in each cell rather than in a single table-level read. This method also does not automatically refresh the table data, which, in our example, would mean the CommsStatus column would not update to reflect the change in the Enabled column.</p>



<p class="wp-block-paragraph">And you might be thinking–why not just have <code>value</code> property in the <strong>EnabledView </strong>set to an in/out param? Despite being an in/out param, this will not actually write back to the desired tag. This is because the table cell is linked to the manually parsed dataset and is not bidirectionally linked to the original tag.</p>



<p class="wp-block-paragraph">For this example, we will implement a Message Handler. The first step <span style="box-sizing: border-box; margin: 0px; padding: 0px;">in imple</span>menting this is to add another input, called <code>row</code>, to <span style="box-sizing: border-box; margin: 0px; padding: 0px;">the</span>&nbsp;<strong>EnabledView</strong>. This will inform the Message Handler what index of the data array to use. Notice that <code>row</code>, not <code>rowIndex</code><em>,</em> is used since <code>rowIndex</code> only uses the rows that are displayed. If there were more cities, this number would differ from <code>row</code> as it would change depending on which page is being viewed.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--40)">Then, on the toggle switch’s component event, we will add a script to trigger the Message Handler being sent [Figure 7]. Finally, on the main table, we will add a Message Handler that takes in the payload and uses that to both write to the tag and refresh the entire table [Figure 8]. After making those changes, toggling the switches writes to the respective tag!</p>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img decoding="async" width="1961" height="608" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-7-1.jpg" alt="Event Configuration on ToggleSwitch." class="wp-image-43081" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-7-1.jpg 1961w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-7-1-300x93.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-7-1-1024x317.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-7-1-768x238.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-7-1-1536x476.jpg 1536w" sizes="(max-width: 1961px) 100vw, 1961px" /><figcaption class="wp-element-caption"><em>Figure </em>7</figcaption></figure>



<figure class="wp-block-image aligncenter size-full is-resized" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img decoding="async" width="1834" height="771" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-8.jpg" alt="Script Configuration on Table." class="wp-image-43082" style="aspect-ratio:2.3817580504786773;width:1198px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-8.jpg 1834w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-8-300x126.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-8-1024x430.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-8-768x323.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-8-1536x646.jpg 1536w" sizes="(max-width: 1834px) 100vw, 1834px" /><figcaption class="wp-element-caption"><em>Figure 8</em></figcaption></figure>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img decoding="async" width="1634" height="830" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-gif-2.gif" alt="Selecting and deselecting parameters in Weather Table." class="wp-image-43158" style="border-top-left-radius:20px;border-top-right-radius:20px;border-bottom-left-radius:20px;border-bottom-right-radius:20px;aspect-ratio:1.9692580386074723;object-fit:contain;width:981px;height:auto"/><figcaption class="wp-element-caption"><em>Figure </em>9</figcaption></figure>



<h3 id="h-column-commsstatus" class="wp-block-heading">Column: CommsStatus</h3>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)">This column will use an icon to indicate the communication status based on both the <code>rowData.CommsStatus</code> and <code>rowData.Enabled</code> properties. To pass that information into the embedded view, we will add <code>rowData</code> as a param to the View [Figure 10].</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="867" height="763" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-10-1.jpg" alt="Perspective Property Editor table." class="wp-image-43087" style="width:730px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-10-1.jpg 867w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-10-1-300x264.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-10-1-768x676.jpg 768w" sizes="(max-width: 867px) 100vw, 867px" /><figcaption class="wp-element-caption"><em>Figure 10</em></figcaption></figure>



<p class="wp-block-paragraph" style="padding-top:var(--wp--preset--spacing--30)">The bindings on the icon property are set up such that:</p>



<ol start="1" class="wp-block-list">
<li>A gray <strong>material/wifi_off </strong>icon indicates the station is disabled.</li>



<li>A gray <strong>material/wifi</strong> icon indicates comms are good and the station is enabled.</li>



<li style="padding-bottom:var(--wp--preset--spacing--50)">A red <strong>material/wifi_off</strong> icon indicates that comms bad and station is enabled.</li>
</ol>



<figure class="wp-block-image aligncenter size-large is-resized"><img decoding="async" width="1024" height="660" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-11-1024x660.jpg" alt="Perspective Expression Structure table." class="wp-image-43088" style="width:730px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-11-1024x660.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-11-300x193.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-11-768x495.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-11.jpg 1113w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Figure 11</em></figcaption></figure>



<p class="wp-block-paragraph" style="padding-top:0;padding-bottom:var(--wp--preset--spacing--50)">Then the color property has the following binding, where the color codes are hardcoded. If you would like to do more advanced CSS handling of the color animations, check out DMC&#8217;s <a href="https://static.dmcinfo.com/blog/17916/custom-css-in-ignition-perspective-getting-started-with-the-stylesheets/">blog on CSS styles</a>.</p>



<figure class="wp-block-image aligncenter size-full"><img decoding="async" width="1548" height="714" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-12.jpg" alt="Perspective Property Editor window." class="wp-image-43089" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-12.jpg 1548w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-12-300x138.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-12-1024x472.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-12-768x354.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-12-1536x708.jpg 1536w" sizes="(max-width: 1548px) 100vw, 1548px" /><figcaption class="wp-element-caption"><em>Figure 12</em></figcaption></figure>



<h3 id="h-column-weather" class="wp-block-heading">Column: Weather</h3>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)">The Weather column will be set up similarly to CommsStatus, but we’ll add an additional input param called <code>color</code>, which is bound to the icon&#8217;s color property [Figure 13]. In the table, in the Weather column, add a&nbsp;<code>viewParam.color</code>&nbsp;and bind it to a new field where users can specify the color of the weather icons [Figure 14].</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-0e47273b wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="624" height="295" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-13-2.jpg" alt="'Color' input parameter in Weather column." class="wp-image-43094" style="aspect-ratio:2.115331288601319;width:783px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-13-2.jpg 624w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-13-2-300x142.jpg 300w" sizes="(max-width: 624px) 100vw, 624px" /><figcaption class="wp-element-caption"><em>Figure 1</em>3</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="433" height="526" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-14-1.jpg" alt="'viewParam' icon color property." class="wp-image-43095" style="aspect-ratio:0.8232120082409496;width:305px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-14-1.jpg 433w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspective-embedded-tables-image-14-1-247x300.jpg 247w" sizes="(max-width: 433px) 100vw, 433px" /><figcaption class="wp-element-caption"><em>Figure 1</em>4</figcaption></figure>
</div>
</div>



<h2 id="h-conclusion" class="wp-block-heading" style="padding-top:var(--wp--preset--spacing--30)">Conclusion</h2>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--50)">With the customization now finalized, the table provides users with a straightforward method for enabling/disabling each city, alongside clear graphical representations for efficient data interpretation. This enhancement streamlines user interactions and helps increase the functionality of the Ignition system.</p>



<figure class="wp-block-image aligncenter size-large"><img decoding="async" width="1024" height="623" src="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5-1024x623.png" alt="Final configured table." class="wp-image-43276" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5-1024x623.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5-300x183.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5-768x467.png 768w, https://static.dmcinfo.com/wp-content/uploads/2026/04/ignition-perspectives-image-5.png 1175w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Figure 15</em></figcaption></figure>



<p class="wp-block-paragraph" style="padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--60)">At DMC, we know how important it is to our clients to have easy-to-understand data visualization. Using embedded views in tables is just one of the many ways engineers at DMC leverage Ignition’s tools to build intuitive screens that provide value to our customers. For more tips and tricks, check out our other blogs where engineers explore more ways to use Ignition’s powerful features.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Need help getting more out of Ignition Perspective? Talk with DMC&#8217;s experts.</strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Discover more about DMC&#8217;s <a href="https://static.dmcinfo.com/our-work/category/service/manufacturing-automation-and-intelligence/ignition/" id="1296">Ignition Perspective</a> capabilities for your <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/" id="420">Manufacturing &amp; Automation</a> operations. Learn how we can help for your next project.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/43002/ignition-perspective-embedded-views-tables-cells/">Ignition Perspective Tricks: Embedded Views in Tables Cells</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>DMC Joins Partnership with Kanoa</title>
		<link>https://static.dmcinfo.com/blog/41404/dmc-joins-partnership-with-kanoa/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Thu, 26 Feb 2026 13:00:00 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[MES]]></category>
		<category><![CDATA[News]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=41404</guid>

					<description><![CDATA[<p>We’re excited to announce that DMC has partnered with Kanoa, expanding our ability to deliver quality MES solutions to our customers. Kanoa is a next-generation Manufacturing Execution System built on Ignition that helps manufacturers improve production visibility, support better decision-making, and advance digital transformation on the plant floor. Through this partnership, DMC can offer clients [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/41404/dmc-joins-partnership-with-kanoa/">DMC Joins Partnership with Kanoa</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">We’re excited to announce that DMC has partnered with <a href="https://static.dmcinfo.com/about/partners/kanoa-partner/">Kanoa</a>, expanding our ability to deliver quality <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/mes-programming/" type="link" id="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/mes-programming/">MES</a> solutions to our customers.</p>



<p class="wp-block-paragraph">Kanoa is a next-generation Manufacturing Execution System built on Ignition that helps manufacturers improve production visibility, support better decision-making, and advance digital transformation on the plant floor. Through this partnership, DMC can offer clients an additional, flexible MES option that complements our existing Ignition-based and custom manufacturing solutions.</p>



<p class="wp-block-paragraph">We’re excited to collaborate with the Kanoa team and see this as a strong fit for many of the manufacturers we work with.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong><strong>Accelerate Your Digital Transformation Journey</strong></strong> with DMC.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Want to learn more about how <a href="https://static.dmcinfo.com/about/partners/kanoa-partner/">Kanoa</a> fits into DMC’s <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/">manufacturing</a> and <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/mes-programming/">MES</a> offerings? <a href="https://static.dmcinfo.com/contact/" id="411">Reach out</a> to our team and discover how we can help with your next automation project.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/41404/dmc-joins-partnership-with-kanoa/">DMC Joins Partnership with Kanoa</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Integrating SharePoint into Ignition: A Practical Guide</title>
		<link>https://static.dmcinfo.com/blog/41408/integrating-sharepoint-into-ignition/</link>
		
		<dc:creator><![CDATA[Kirsten Zimmerle]]></dc:creator>
		<pubDate>Thu, 19 Feb 2026 13:00:00 +0000</pubDate>
				<category><![CDATA[Digital Workplace Solutions]]></category>
		<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[SharePoint]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=41408</guid>

					<description><![CDATA[<p>Why SharePoint + Ignition? Integrating SharePoint into Ignition can reduce friction between organizational teams without compromising system reliability. The core draw is bringing enterprise information closer to operations and reducing manual work like exporting reports, emailing files, hunting for the latest SOP, or duplicating data across systems. In some organizations, SharePoint may already be the [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/41408/integrating-sharepoint-into-ignition/">Integrating SharePoint into Ignition: A Practical Guide</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="h-why-sharepoint-ignition" class="wp-block-heading">Why SharePoint + Ignition?</h2>



<p class="wp-block-paragraph">Integrating SharePoint into Ignition can reduce friction between organizational teams without compromising system reliability. The core draw is bringing enterprise information closer to operations and reducing manual work like exporting reports, emailing files, hunting for the latest SOP, or duplicating data across systems.</p>



<p class="wp-block-paragraph">In some organizations, SharePoint may already be the system of record. As part of the Microsoft suite of tools, it is depended on for document management and collaboration. In this case, integrating SharePoint into Ignition can expand system capabilities to leverage the strengths of each tool and reduce separation or duplication between operation/production and other teams.</p>



<p class="wp-block-paragraph">Other organizations may be looking to move away from paper-driven or manual processes. In these cases, the combination of Ignition and SharePoint can allow the concerns of both manual production or record keeping and old-fashioned document storage and sharing to be addressed in a way that sets teams up for lower overhead.</p>



<h2 id="h-what-ignition-and-sharepoint-each-do-best" class="wp-block-heading">What Ignition and SharePoint Each Do Best</h2>



<p class="wp-block-paragraph">As a SCADA platform, Ignition excels at real-time and near-real-time operations. It connects to control system components, surfacing information to users in a way that is conducive to effective and efficient decision-making during operation. Additionally, it’s built around SQL database connectivity rather than proprietary data storage formats. It natively integrates with databases such as PostgreSQL, Microsoft SQL Server, and MySQL, enabling robust historical data logging, reporting, and analytics. This makes it well-suited for data-driven applications and integration with other data analytics tools. Ignition also supports Python scripting throughout the platform, allowing engineers and developers to build custom logic, automation routines, and integrations. Its API-driven design and flexible UI development tools enable deep customization, making it adaptable.</p>



<p class="wp-block-paragraph">SharePoint, on the other hand, is designed for document handling and collaboration. At its core, SharePoint provides a centralized and structured environment for storing, organizing, and managing digital content across an organization. Unlike traditional file servers, it layers document management capabilities such as version control, metadata, and permissions directly onto cloud-based storage, making information both more accessible and more governable. Its built-in search engine further strengthens this by allowing users to retrieve relevant documents and data across sites, libraries, and even connected Microsoft 365 services. Procedures, manuals, reports, and audit artifacts all fit naturally into SharePoint’s structure and methodology. Beyond document storage, SharePoint serves as a flexible platform for building internal portals and collaborative workspaces, with sites acting as hubs for departments or projects and Power Automate integration providing options for automating workflows like approvals, document routing, and notifications.</p>



<p class="wp-block-paragraph">The value in integration between these two systems comes from exposing information between them, while allowing each to preside over the scope of work it was designed for. When humans are in the loop doing document management, approvals, or reviewing reports, integrating SharePoint into Ignition provides benefits in terms of transparency between teams and the reduction of duplicated data.</p>



<h2 id="h-common-integration-use-cases" class="wp-block-heading">Common Integration Use Cases</h2>



<h3 id="h-publishing-reports" class="wp-block-heading">Publishing Reports</h3>



<p class="wp-block-paragraph">One common pattern for integration is publishing content out of Ignition. Scheduled reports, batch summaries, or downtime logs can be automatically uploaded to a SharePoint document library where supervisors and engineers already expect to find them.</p>



<p class="wp-block-paragraph">From a technical standpoint, this typically involves formatting data into a document and then using Ignition’s scripting capabilities and SharePoint’s APIs (such as Microsoft Graph or SharePoint REST endpoints) to programmatically upload the files to the appropriate SharePoint site, folder, or document library. Metadata — such as production line, batch ID, timestamp, shift, or product type — can be attached to each file on upload, making the content easier to search, filter, and organize.</p>



<p class="wp-block-paragraph">This allows other organizational teams or team members – such as engineers or managers &#8211; to access the latest production summaries, downtime logs, or performance reports directly from SharePoint, alongside other operational and business documents. This creates a more unified information flow between OT (operational technology) and IT systems, which reduces separation or duplication between plant-floor data and enterprise documentation.</p>



<p class="wp-block-paragraph">Additionally, storing Ignition-generated content in SharePoint enables downstream workflows. For example, the arrival of a new batch summary could automatically trigger a review or approval process via Power Automate, notify stakeholders in Microsoft Teams, or be archived according to corporate retention policies. Over time, this turns SharePoint into not just a storage location, but an active collaboration and governance layer for industrial data.</p>



<h3 id="h-document-display-in-ignition" class="wp-block-heading">Document Display in Ignition</h3>



<p class="wp-block-paragraph">Another high-value use case for integrating SharePoint with Ignition is using SharePoint as the authoritative source of documentation and then surfacing that information directly within Ignition’s operator interface. In many facilities, critical operational information — such as standard operating procedures (SOPs), wiring diagrams, and manuals — requires formal version control, approvals, and periodic reviews, making SharePoint a natural system of record. However, operators and technicians typically spend most of their time inside Ignition HMIs rather than browsing SharePoint sites. If they must leave the HMI to search for documents, it can cause frustration and increase the likelihood that outdated or unofficial copies will be used.</p>



<p class="wp-block-paragraph">Through integration, Ignition screens can dynamically link to or embed documents that reside in SharePoint. Technically, this can be accomplished by storing document URLs or metadata in Ignition and using web views or API calls to retrieve the correct file from SharePoint in real time. The system can also be designed to filter documents, so&nbsp;users see only the most relevant information. For example, when an operator selects a specific piece of equipment in Ignition, the screen could automatically display the latest approved maintenance checklist associated with that asset.</p>



<p class="wp-block-paragraph">Because the documents remain managed in SharePoint, this approach preserves strong governance without sacrificing usability. SharePoint’s built-in versioning ensures that only the most current, approved documents are presented, while historical versions remain available for auditing or reference. Approval workflows, document review cycles, and change tracking can all continue to operate in SharePoint, independent of Ignition. From the operator’s perspective, however, they simply see the right document in the right place at the right time, embedded seamlessly within their normal workflow.</p>



<p class="wp-block-paragraph">This integration also improves consistency and reduces risk. Instead of multiple copies of procedures floating around on local drives or printed binders, there is a single, controlled source of truth in SharePoint that is directly connected to the HMI. If a procedure is updated due to a safety change or process improvement, the new version becomes instantly available to all operators through Ignition without requiring manual redistribution.</p>



<h3 id="h-exception-log-tracking" class="wp-block-heading">Exception Log Tracking</h3>



<p class="wp-block-paragraph">Some teams leverage SharePoint lists as a lightweight mechanism to capture operational information that is important from a business, quality, or compliance perspective but not critical to real-time control. Instead of pushing everything into an industrial database or embedding every data-capture requirement directly into Ignition, teams use SharePoint as a parallel system for structured tracking of contextual or administrative records that surround plant activity.</p>



<p class="wp-block-paragraph">In practice, this often includes exception logs, operator notes, minor deviations, near-miss reports, shift comments, maintenance observations, or non-critical audit records. These are pieces of information that benefit from being organized, searchable, and reviewable across departments, but do not require the speed, determinism, or reliability guarantees of a control system database. SharePoint lists are well-suited for this because they allow teams to define custom fields, validation rules, and views without requiring a dedicated application.</p>



<p class="wp-block-paragraph">Integration with Ignition in this scenario usually takes the form of one-way or loosely coupled data exchange. For example, Ignition might provide an operator interface that allows users to submit an exception entry or add contextual notes about a process event. Behind the scenes, Ignition scripts or API calls then create or update corresponding entries in a SharePoint list via Microsoft Graph or SharePoint’s REST endpoints. Alternatively, Ignition could automatically log certain classes of events — such as repeated minor alarms or operator overrides — into SharePoint for later review by supervisors or quality teams.</p>



<p class="wp-block-paragraph">The critical design principle in this pattern is that SharePoint remains outside of the control loop. Ignition continues to handle all real-time monitoring, interlocking, alarming, and automation logic, while SharePoint serves as a complementary system with improved visibility for team collaboration. Operations teams retain a responsive, high-performance control environment in Ignition, while IT and quality teams gain structured, shareable records in SharePoint that can be integrated with broader business processes. Over time, this creates a balanced ecosystem where industrial data and human-centered documentation coexist without overloading the control system with non-operational responsibilities.</p>



<h2 id="h-integration-approaches-and-architecture" class="wp-block-heading">Integration Approaches and Architecture</h2>



<p class="wp-block-paragraph">Most SharePoint integrations with Ignition are built around API access using either the SharePoint REST API or Microsoft Graph API, which are invoked directly from Ignition scripting. SharePoint’s APIs expose a robust integration surface that allows external systems to programmatically interact with SharePoint as a structured content and data platform. Through standard web-based endpoints, external applications can create, read, update, and delete sites, document libraries, files, and list items, and manage metadata, permissions, and versioning. All interactions are secured through Entra ID authentication and role-based access controls, ensuring that integrations follow the same security policies as human users.</p>



<p class="wp-block-paragraph">Within Ignition, this connectivity is implemented through its Python-based scripting environment, which can issue HTTP requests to these APIs. Using built-in networking functions or third-party libraries, Ignition scripts can transmit data and handle responses in real time. This enables Ignition to reliably read from and write to SharePoint while staying tightly aligned with Ignition events, tags, and transaction logic.</p>



<p class="wp-block-paragraph">Generally, a middleware layer that handles authentication and API complexity is also required. This can take the form of a simple web service, server-less compute function, or gateway-hosted service and helps to manage authentication tokens and segregate concerns. As an example, this might take the form of a Python application that runs on the ignition gateway, with the following flow:</p>



<figure class="wp-block-image size-full"><img decoding="async" width="918" height="534" src="https://static.dmcinfo.com/wp-content/uploads/2026/02/IgnitionToSharePointSequenceDiagram.png" alt="Ignition to SharePoint Sequence Diagram" class="wp-image-41418" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/02/IgnitionToSharePointSequenceDiagram.png 918w, https://static.dmcinfo.com/wp-content/uploads/2026/02/IgnitionToSharePointSequenceDiagram-300x175.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/02/IgnitionToSharePointSequenceDiagram-768x447.png 768w" sizes="(max-width: 918px) 100vw, 918px" /></figure>



<h2 id="h-integration-considerations" class="wp-block-heading">Integration Considerations</h2>



<h3 id="h-governance-and-ownership" class="wp-block-heading">Governance and Ownership</h3>



<p class="wp-block-paragraph">As is common when tools are bridging the gaps between organizational teams, it is worthwhile to consider who is responsible for maintaining each part of the solution long-term. In the case of this integration, it is likely that the controls or operations team will own the Ignition side of the system, including screens, control logic, and scripts, while IT will own the SharePoint side, including permissions/authentication and structure. Defining the boundary and interface between these two sides to the integration explicitly can reduce friction and maintenance overhead down the line. Things to consider:</p>



<ul class="wp-block-list">
<li>Folder structures and naming conventions</li>



<li>Retention and archiving rules</li>



<li>The change management process</li>
</ul>



<h3 id="h-authentication-and-security" class="wp-block-heading">Authentication and Security</h3>



<p class="wp-block-paragraph">Ignition authenticates to SharePoint as an application (rather than receiving delegated permissions from a user log-in) using a dedicated service account. This requires setting up an app registration in Azure Entra ID, with the following basic steps:</p>



<ol class="wp-block-list">
<li><strong>Create a New App Registration in Entra ID via the Azure Portal</strong>
<ul class="wp-block-list">
<li>At this point, Entra ID creates the application identity with an Application (client) ID and Directory (tenant) ID. These values are important for later configuration.</li>
</ul>
</li>



<li><strong>Add a Certificate</strong>
<ul class="wp-block-list">
<li>You must prove the app’s identity when requesting tokens. Go to “Certificates &amp; secrets” and upload a certificate; the thumbprint and private key for this certificate will later be used to authenticate.</li>
</ul>
</li>



<li><strong>Assign API Permissions (Scopes)</strong>
<ul class="wp-block-list">
<li>This defines what the app is allowed to do. Common examples include: <em>Sites.ReadWrite.All</em> (to create/update files and lists) or <em>User.Read.All</em> &nbsp;(to read user profiles).</li>
</ul>
</li>



<li><strong>Grant Admin Consent</strong>
<ul class="wp-block-list">
<li>Most SharePoint/Graph permissions require tenant-wide approval. Without this, your app will not be able to access SharePoint in most enterprise tenants.</li>
</ul>
</li>



<li><strong>Use These Values in Your Integration</strong>
<ul class="wp-block-list">
<li>You will typically need the following to acquire access tokens from Entra ID:
<ul class="wp-block-list">
<li>Tenant ID</li>



<li>Client (Application) IDCertificate (thumbprint + private key)</li>



<li>Certificate (thumbprint + private key)</li>



<li>API Scopes (e.g., Graph&#8217;s User.Read or SharePoint&#8217;s Sites.ReadWrite.All)</li>
</ul>
</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">In addition to setting up an app registration for Ignition, general security guidance, such as not hardcoding credentials and using the lowest permissions required are important for implementing the integration as securely as possible.</p>



<h3 id="h-expectations-and-error-handling" class="wp-block-heading">Expectations and Error Handling</h3>



<p class="wp-block-paragraph">Ensuring the usefulness of the integration depends on keeping expectations aligned with what each tool is good at and implementing robust error handling to account for connectivity issues. For instance, it is reasonable to expect SharePoint to handle files and metadata in a batched or event-driven way. SharePoint excels at handling files and list-formatted data, and API based access aligns well with low-frequency updates. However, it would not be reasonable to use SharePoint to store high-frequency operational data or to act as a data historian; it is not set up to handle streams of data, and it is not optimized for time-series information. Similarly, it is likely reasonable to expect that the normal operational state of the system would be Ignition and SharePoint communicating with relatively low response times, but likely not reasonable to assume perfect connectivity or 100% uptime.</p>



<p class="wp-block-paragraph">To this end, it is valuable to implement handling to account for cases that would differ from the reasonable expectations for the system. This could include:</p>



<ul class="wp-block-list">
<li>Including timeouts to prevent calls from blocking indefinitely,</li>



<li>Clear logging for failures,</li>



<li>Retry logic; likely with limits on the total number of retries,</li>



<li>Caching of queried data (like SOP’s or manuals) when practical</li>
</ul>



<p class="wp-block-paragraph">Considering these cases allows the overall system to continue functioning as smoothly as possible when something goes wrong, and forethought into failure handling allows for a simpler debugging process.</p>



<h2 id="h-building-your-sharepoint-and-ignition-integration" class="wp-block-heading">Building Your SharePoint and Ignition Integration</h2>



<p class="wp-block-paragraph">Integrating Ignition with SharePoint in a secure, scalable, and maintainable way is technically feasible for many organizations, but doing it well often requires a blend of OT, IT, and cloud expertise that rarely exists fully within a single team. For this reason, working with an experienced consulting partner like DMC can be highly valuable when undertaking this type of integration.</p>



<p class="wp-block-paragraph">A knowledgeable partner brings deep, practical experience with both Ignition and the Microsoft ecosystem. This helps avoid common pitfalls around integration interfaces and authentication. Rather than learning through trial and error, organizations benefit from proven design patterns and best practices that have been refined across multiple projects and industries. DMC maintains <a href="https://static.dmcinfo.com/about/partners/ignition-premier-integrator/">Ignition Premier Integrator</a> status and <a href="https://static.dmcinfo.com/about/partners/microsoft-solutions-partner/">Microsoft Solutions Partner</a> status and has extensive experience developing solutions in both <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">Ignition</a> and <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/sharepoint/">SharePoint</a>. Additionally, DMC’s diverse experience across both <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/ignition-programming/">manufacturing/OT</a> and <a href="https://static.dmcinfo.com/services/digital-workplace-solutions">business-centric/IT</a> projects enables us to facilitate conversations between organizational teams and stakeholders, ensuring the solution is designed in a way that works for all users. This cross-functional perspective is often just as important as the code itself.</p>



<p class="wp-block-paragraph">Finally, working with a partner accelerates delivery. Instead of dedicating internal resources to building and troubleshooting unfamiliar components, teams can focus on their core responsibilities while the consultant handles the complexity of the integration. The result is a more robust solution delivered faster, with a clearer path for future enhancements.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong><strong>Ready to expand your SharePoint or Ignition capabilities? </strong></strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Unlock greater collaboration and visibility for your SharePoint project with DMC. Learn more about our <a href="https://static.dmcinfo.com/our-work/category/service/manufacturing-automation-and-intelligence/ignition/" data-type="work_category" data-id="1296">Ignition</a> expertise for your <a href="https://static.dmcinfo.com/services/digital-workplace-solutions/" data-type="page" data-id="437">Digital Workplace Solutions</a> operations.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/41408/integrating-sharepoint-into-ignition/">Integrating SharePoint into Ignition: A Practical Guide</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Top Takeaways from ICC 2025: What DMC Learned and What It Means for You</title>
		<link>https://static.dmcinfo.com/blog/39026/top-takeaways-from-icc-2025-what-dmc-learned-and-what-it-means-for-you/</link>
		
		<dc:creator><![CDATA[David Berno]]></dc:creator>
		<pubDate>Wed, 08 Oct 2025 22:27:30 +0000</pubDate>
				<category><![CDATA[Ignition]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=39026</guid>

					<description><![CDATA[<p>The Ignition Community Conference (ICC) was a blast this year. Hosted at Sacramento’s SAFE Credit Union Convention Center, Inductive Automation definitely leveled up this year. From technical deep dives to forward-looking industry discussions, ICC 2025 delivered plenty of insight and inspiration. DMC has condensed our key takeaways that we believe will have the biggest impact [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/39026/top-takeaways-from-icc-2025-what-dmc-learned-and-what-it-means-for-you/">Top Takeaways from ICC 2025: What DMC Learned and What It Means for You</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-columns alignwide is-layout-flex wp-container-core-columns-is-layout-0e47273b wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<p class="wp-block-paragraph">The <a href="https://icc.inductiveautomation.com/">Ignition Community Conference (ICC)</a> was a blast this year. Hosted at Sacramento’s SAFE Credit Union Convention Center, Inductive Automation definitely leveled up this year. From technical deep dives to forward-looking industry discussions, ICC 2025 delivered plenty of insight and inspiration. DMC has condensed our key takeaways that we believe will have the biggest impact on our customers.</p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img decoding="async" width="2560" height="1107" src="https://static.dmcinfo.com/wp-content/uploads/2025/10/icc-2025-level-up.jpg" alt="DMC at ICC 2025" class="wp-image-38937" style="border-radius:21px;width:529px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2025/10/icc-2025-level-up.jpg 2560w, https://static.dmcinfo.com/wp-content/uploads/2025/10/icc-2025-level-up-300x130.jpg 300w, https://static.dmcinfo.com/wp-content/uploads/2025/10/icc-2025-level-up-1024x443.jpg 1024w, https://static.dmcinfo.com/wp-content/uploads/2025/10/icc-2025-level-up-768x332.jpg 768w, https://static.dmcinfo.com/wp-content/uploads/2025/10/icc-2025-level-up-1536x664.jpg 1536w, https://static.dmcinfo.com/wp-content/uploads/2025/10/icc-2025-level-up-2048x886.jpg 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>
</div>
</div>
</div>



<h2 id="h-8-3-is-here" class="wp-block-heading">8.3 is Here</h2>



<p class="wp-block-paragraph">8.3 made a big splash on the first day of the conference with the official release. And it was everything that we had been waiting for. Earlier this year, we did a deep dive in this <a href="https://static.dmcinfo.com/blog/15670/ignition-8-3-whats-new-and-reasons-to-upgrade-your-project/">Ignition 8.3 – What’s New and Reasons to Upgrade Your Project</a> blog on what we were most excited about in Ignition 8.3, and the initial release did not disappoint. DMC is excited to continue working with our clients on their upgrade strategy, enabling them to maximize the benefits of these new features and get the most out of it.</p>



<h2 id="h-modern-deployment-methods" class="wp-block-heading">Modern Deployment Methods</h2>



<p class="wp-block-paragraph">One of the most anticipated aspects of 8.3 is its support for modern deployment workflows. From the new Gateway setting for deployment modes, to text-based project files – 8.3 is made for a DevOps workflow. DMC is eager to take advantage of this to make deploying changes to production more reliable.</p>



<h2 id="h-mes-is-on-the-rise" class="wp-block-heading">MES is on the Rise</h2>



<p class="wp-block-paragraph">More and more Discovery Gallery projects and technical sessions were focused on core <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/mes-programming/">Manufacturing Execution System (MES) </a>functions such as <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/mes-programming/oee-and-downtime-tracking/">Overall Equipment Effectiveness (OEE)</a>, <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/mes-programming/track-and-trace-mes-integration/">product traceability</a>, batch control, inventory management, <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/mes-programming/mes-erp-integration/">ERP system integration</a>, and production scheduling.&nbsp;Ignition is clearly evolving beyond traditional <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/hmi-and-scada-programming/">HMI and SCADA </a>into complex, plant-wide operational systems. Since many Ignition installations already collect valuable production data, DMC is excited to continue helping customers harness that data for greater visibility, optimization, and continuous improvement through MES functionality.</p>



<h2 id="h-inductive-is-revolutionizing-scada-licensing-models-again" class="wp-block-heading">Inductive is Revolutionizing SCADA Licensing Models Again</h2>



<p class="wp-block-paragraph">Inductive Automation is once again transforming how SCADA systems are licensed. The new Ignition Solution Suites simplify the buying process by grouping modules around specific functionality goals. Even more impactful, these suites are future-proof—if new modules are added to a suite, existing Solution Suite license purchasers automatically gain access. This model will make it easier and more cost-effective for customers to adopt new capabilities as they’re released.</p>



<h2 id="h-ai-is-coming" class="wp-block-heading">AI is Coming</h2>



<p class="wp-block-paragraph">The big buzzword nowadays is, of course, AI. With the steady adoption of AI, the importance of factory floor data is even greater. Inductive introduced an upcoming Model Context Protocol (MCP) module, which is designed to bridge Ignition with AI systems. This integration could unlock powerful new ways to use real-time data for predictive insights and process optimization.</p>



<h2 id="h-see-you-at-icc-2026" class="wp-block-heading">See You at ICC 2026</h2>



<p class="wp-block-paragraph">DMC is continuously exploring new ways to push the boundaries of Ignition, and ICC 2025 gave us a lot of new features and ideas that we are excited to bring back to our clients. Less than a year until the next ICC!</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step">At DMC, You Can Find Ignition Expertise You Can Trust.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">See how you can develop your <a href="https://static.dmcinfo.com/about/partners/ignition-premier-integrator/">Ignition project</a> with DMC&#8217;s <a href="https://static.dmcinfo.com/services/manufacturing-automation-and-intelligence/" id="420">automation</a> experts. <a href="https://static.dmcinfo.com/contact/">Contact us today</a> to learn more about our solutions and how we can advance your next project.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph"><a id="_msocom_1"></a></p>



<p class="wp-block-paragraph"><a id="_msocom_1"></a></p>



<p class="wp-block-paragraph"><a id="_msocom_1"></a></p>
<p>The post <a href="https://static.dmcinfo.com/blog/39026/top-takeaways-from-icc-2025-what-dmc-learned-and-what-it-means-for-you/">Top Takeaways from ICC 2025: What DMC Learned and What It Means for You</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
