<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>HMI on Loupe Documentation</title>
    <link>/hmi.html</link>
    <description>Recent content in HMI on Loupe Documentation</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language><atom:link href="/hmi/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Architecture</title>
      <link>/hmi/architecture.html</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/hmi/architecture.html</guid>
      <description>&lt;p&gt;A LuxReact HMI has four layers.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Layer&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Component&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Job&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;UI binding&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/loupeteam/LuxReact&#34;&gt;LuxReact&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Connects React components to variables with hooks&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Client&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/loupeteam/LuxConnect&#34;&gt;LuxConnect&lt;/a&gt; &lt;code&gt;OpcuaMachine&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Manages the session, subscriptions, and value cache&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Transport&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;HTTPS REST plus a WebSocket push channel&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Carries reads, writes, and updates&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Gateway&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;mapp Connect or &lt;a href=&#34;../hmi/gateways.html&#34;&gt;OPC UA Proxy&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Reads and writes variables on the controller over OPC UA&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div class=&#34;mermaid&#34; align=&#34;center&#34;&gt;
flowchart TD
    subgraph App[&#34;Browser or Electron&#34;]
        UI[React components] --&gt;|useVariable / useWrite| LR[LuxReact&lt;br/&gt;MachineProvider]
        LR --&gt;|ICommLayer| LC[LuxConnect&lt;br/&gt;OpcuaMachine]
    end
    LC --&gt;|&#34;REST: sessions, read, write&#34;| GW{Gateway}
    GW -.-&gt;|&#34;WebSocket push channel&#34;| LC
    GW --&gt;|B&amp;R| MC[mapp Connect&lt;br/&gt;on the controller] --&gt; BR[(B&amp;R PLC)]
    GW --&gt;|&#34;Other OPC UA&#34;| P[OPC UA Proxy&lt;br/&gt;on a PC or in Electron] --&gt; OS[OPC UA server] --&gt; PLC[(Beckhoff or other PLC)]
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LuxReact&lt;/strong&gt; handles the React side: providers, hooks, subscription bookkeeping, and caching values across remounts. It does not know how values reach the PLC. It talks to an &lt;code&gt;ICommLayer&lt;/code&gt; interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LuxConnect&lt;/strong&gt; is the &lt;code&gt;ICommLayer&lt;/code&gt; implementation. It opens an OPC UA session through the gateway, subscribes to variables, and receives changes over the push channel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The gateway&lt;/strong&gt; is mapp Connect on a B&amp;amp;R controller, or OPC UA Proxy for other OPC UA servers. Both offer the same API, so the HMI code is the same either way.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because LuxReact only depends on &lt;code&gt;ICommLayer&lt;/code&gt;, a different transport means writing a different adapter. The React code stays the same. LuxReact ships a &lt;code&gt;MockCommLayer&lt;/code&gt; for tests and component previews.&lt;/p&gt;</description>
    </item>
    <item>
      <title>LuxReact &#43; LuxConnect</title>
      <link>/hmi/lux-react.html</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/hmi/lux-react.html</guid>
      <description>&lt;p&gt;LuxReact and LuxConnect are the recommended stack for new HMIs on B&amp;amp;R controllers. Both are written in TypeScript and are in active development, so their APIs may change before 1.0.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Package&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Repository&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;What it does&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;@loupeteam/lux-react&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/loupeteam/LuxReact&#34;&gt;LuxReact&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;React providers and hooks. Works with any transport that implements &lt;code&gt;ICommLayer&lt;/code&gt;.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;@loupeteam/lux-connect&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/loupeteam/LuxConnect&#34;&gt;LuxConnect&lt;/a&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;OPC UA client for B&amp;amp;R mapp Connect. Also usable without React, in Node.js or the browser.&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The repository READMEs are the API reference. This page covers how the pieces fit together.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Gateways</title>
      <link>/hmi/gateways.html</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/hmi/gateways.html</guid>
      <description>&lt;p&gt;LuxConnect talks to a gateway that offers the mapp Connect API. The gateway reads and writes variables on the controller.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Gateway&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Runs on&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Controller&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Protocol to controller&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;mapp Connect&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;B&amp;amp;R controller&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;B&amp;amp;R&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Built into Automation Runtime&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;OPC UA Proxy (experimental)&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;PC, or inside an Electron HMI&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Controllers without mapp Connect, through their OPC UA server&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;OPC UA&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;mapp-connect&#34;&gt;mapp Connect&lt;/h2&gt;
&lt;p&gt;mapp Connect is part of B&amp;amp;R mapp and runs on the controller. See &lt;a href=&#34;../hmi/lux-react.html&#34;&gt;LuxReact + LuxConnect&lt;/a&gt; for the controller setup.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Users and login</title>
      <link>/hmi/users-and-login.html</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/hmi/users-and-login.html</guid>
      <description>&lt;p&gt;Users and roles live on the OPC UA server. On a B&amp;amp;R controller, define them in the Automation Studio project under &lt;strong&gt;Access and Security&lt;/strong&gt;. When the HMI connects, LuxConnect opens an OPC UA session as a user, and the server applies that user&amp;rsquo;s permissions to every read and write.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sign in with &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; when you create the &lt;code&gt;OpcuaMachine&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Switch users without reconnecting with &lt;code&gt;machine.changeUser(username, password)&lt;/code&gt;. Call &lt;code&gt;changeUser()&lt;/code&gt; with no arguments to switch to the anonymous user.&lt;/li&gt;
&lt;li&gt;Read the current user and roles with &lt;code&gt;machine.getSessionInfo()&lt;/code&gt;. Use the roles to show or hide screens.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the server checks every request, hiding a button is only a convenience. A user without permission can&amp;rsquo;t write the variable even if they reach it another way.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Platform support</title>
      <link>/hmi/platform-support.html</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/hmi/platform-support.html</guid>
      <description>&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Controller&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Support&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Gateway&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;B&amp;amp;R Automation Runtime&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Supported&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;mapp Connect&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Beckhoff TwinCAT 3&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Experimental&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;OPC UA Proxy and the TwinCAT OPC UA server (TF6100)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Other OPC UA controllers&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Experimental&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;OPC UA Proxy&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;beckhoff&#34;&gt;Beckhoff&lt;/h2&gt;
&lt;p&gt;LuxConnect talks to the B&amp;amp;R mapp Connect API, so it can&amp;rsquo;t connect to a TwinCAT controller directly. &lt;a href=&#34;../hmi/gateways.html&#34;&gt;OPC UA Proxy&lt;/a&gt; fills that gap: it offers the mapp Connect API and forwards requests to the TwinCAT OPC UA server.&lt;/p&gt;
&lt;p&gt;This path has not been validated on TwinCAT yet. Variable naming and namespaces differ from B&amp;amp;R, so test reads, writes, and structures on your controller before committing a project to it.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Migrating to LuxReact</title>
      <link>/hmi/migrating.html</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/hmi/migrating.html</guid>
      <description>&lt;div class=&#34;box notices cstyle info&#34;&gt;
    &lt;div class=&#34;box-label&#34;&gt;&lt;i class=&#34;fa-fw fas fa-info-circle&#34;&gt;&lt;/i&gt; Info&lt;/div&gt;
    &lt;div class=&#34;box-content&#34;&gt;
&lt;p&gt;This guide is a starting point. It will grow as HMIs are migrated.&lt;/p&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Moving from Loupe UX classic to LuxReact is a rewrite of the UI, plus a change on the controller. Plan it as a project, not an upgrade.&lt;/p&gt;
&lt;h2 id=&#34;controller-changes&#34;&gt;Controller changes&lt;/h2&gt;
&lt;p&gt;On B&amp;amp;R:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable mapp Connect and the OPC UA server. See &lt;a href=&#34;../hmi/lux-react.html&#34;&gt;LuxReact + LuxConnect&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make every variable the HMI uses visible over OPC UA.&lt;/li&gt;
&lt;li&gt;Move user handling to OPC UA users and roles. See &lt;a href=&#34;../hmi/users-and-login.html&#34;&gt;Users and login&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On Beckhoff, the target is &lt;a href=&#34;../hmi/gateways.html&#34;&gt;OPC UA Proxy&lt;/a&gt; with the TwinCAT OPC UA server. That path is experimental, so keep Loupe UX Server running until it is validated on your controller.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Loupe UX classic (deprecated)</title>
      <link>/hmi/lux-classic.html</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/hmi/lux-classic.html</guid>
      <description>&lt;p&gt;Loupe UX classic is deprecated. Existing HMIs remain supported, but start new HMIs on &lt;a href=&#34;../hmi/lux-react.html&#34;&gt;LuxReact + LuxConnect&lt;/a&gt;, and see &lt;a href=&#34;../hmi/migrating.html&#34;&gt;Migrating to LuxReact&lt;/a&gt; to move an existing one.&lt;/p&gt;
&lt;p&gt;Loupe UX is the original Loupe web HMI library. You build pages in HTML and connect elements to PLC variables with attributes. It needs no build step and no JavaScript framework beyond jQuery.&lt;/p&gt;
&lt;h2 id=&#34;architecture&#34;&gt;Architecture&lt;/h2&gt;

&lt;div class=&#34;mermaid&#34; align=&#34;center&#34;&gt;
flowchart TD
    subgraph Page[&#34;Browser or Electron&#34;]
        HTML[&#34;HTML elements&lt;br/&gt;data-var-name&#34;] --&gt; DB[lux-data-bind.js]
        DB --&gt; M[lux.js&lt;br/&gt;LUX.Machine]
    end
    M &lt;--&gt;|&#34;JSON over WebSocket&#34;| OM[OMJSON&lt;br/&gt;on the B&amp;R PLC]
    M &lt;--&gt;|&#34;JSON over WebSocket&#34;| LS[Loupe UX Server&lt;br/&gt;Windows PC] &lt;--&gt;|ADS| TC[(TwinCAT 3)]
&lt;/div&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Component&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Runs on&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Documentation&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Loupe UX (&lt;code&gt;lux.js&lt;/code&gt;, &lt;code&gt;lux-data-bind.js&lt;/code&gt;, &lt;code&gt;lux.css&lt;/code&gt;)&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Browser or Electron&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;../libraries/loupe-ux.html&#34;&gt;Loupe UX Web Client&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Tmplits (optional)&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Browser or Electron&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;../libraries/tmplitdocs.html&#34;&gt;Tmplits&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;OMJSON&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;B&amp;amp;R controller&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;../libraries/omjson.html&#34;&gt;OMJSON&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Loupe UX Server&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Windows PC with an ADS route to a Beckhoff controller&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;../hmi/lux-classic.html#loupe-ux-server&#34;&gt;Loupe UX Server&lt;/a&gt; below&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Loupe UX scans the page for elements with &lt;code&gt;data-var-name&lt;/code&gt; and reads those variables over a WebSocket. Call &lt;code&gt;LUX.updateHMI()&lt;/code&gt; on a timer to refresh the page. Use &lt;a href=&#34;../libraries/loupe-ux/optimizing-communication.html&#34;&gt;read groups&lt;/a&gt; to limit how much is read and how often.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>