Upload HTML to Screen Files and open it from a runtime menu. Runtime loads the SDK; no npm package or extra script is needed. Call ready() once and reuse api.
Developer guide
Developer guide: Page SDK: quick start
Use the Page SDK to read Tags, write setpoints, and query alarms and trends. The HTML and Vue examples require project Tag codes and permission checks before publishing.
How the SDK loads
Upload HTML to Screen Files and open it from a runtime menu. Runtime loads the SDK; no npm package or extra script is needed. Call ready() once and reuse api.
JavaScriptJavaScript
HQVISU_CUSTOM_PAGE.ready().then(async (api) => { // Use the examples below here. Reuse this api object.}).catch(error => console.error(error.message));
Expected result In plain HTML, place the script at the end of body, after the page elements. Add selected snippets to the same async callback and reuse api. Standalone Vite servers, file://, and other sites do not provide this runtime.
Put this declaration in the entry HTML head. Replace <device-code>.<tag-code> with the actual full code. Use writableTags: [] for a read-only page. For Vue, put it in index.html.
Expected result layoutMode: "native" lets plain HTML/Vue use a responsive viewport layout. readableTags declares reads; writableTags declares writes. A declaration does not grant control permissions to the account.
Read a Tag
Add <output id="value"></output>. Read numbers with ReadTagDouble and use null for unavailable data. Use ReadTagInteger, ReadTagBoolean, or ReadTagString for other types.
JavaScriptJavaScript
const value = api.ReadTagDouble("<device-code>.<tag-code>", null);document.getElementById("value").textContent = value ?? "—";
Expected result The call synchronously reads the latest collected value without polling the PLC. Display null as “—”, not a real zero.
Update when the value changes
Add <output id="value"></output> to the HTML and use subscribe to refresh it. No setInterval polling is needed.
JavaScriptJavaScript
const tag = "<device-code>.<tag-code>";function renderValue() { const value = api.ReadTagDouble(tag, null); document.getElementById("value").textContent = value ?? "—";}renderValue();const stop = api.subscribe([tag], renderValue);// Call stop() when this view is removed.
Expected result The value renders immediately and updates on change. Call stop() when the view is removed.
Write a Tag once from a button
Add <button id="write" disabled>Write</button> and <pre id="result"></pre>. This writes 12.5 once; replace it with an allowed value. Declare the writable Tag, enable its control flag and use an account with tag:write permission.
Expected result Use WriteTagInteger or WriteTagBoolean for those types. This example submits once per page instance, then disables the button; done still requires later normal collection. Reloading resets the button. Reconcile the prior result before another action; persist pending-verification state if blocking must survive reloads.
Expected result This queries once. For live lists, use alarms.subscribe to trigger a new query, without appending callback data; unsubscribe on exit. Empty items means no alarms in scope; hasMore=true means more records. Configure scope for other devices or groups.
Add <div id="alarm-history"></div> and <p id="history-status"></p>. Use alarms.queryHistory to display historical events in a separate table.
JavaScriptJavaScript
const alarmEnd = new Date();const alarmHistory = await api.alarms.queryHistory({ start: new Date(alarmEnd.getTime() - 3600000).toISOString(), end: alarmEnd.toISOString(), limit: 100});api.renderTable("#alarm-history", alarmHistory.items);document.getElementById("history-status").textContent = alarmHistory.hasMore ? "More records available" : "";
Query trend data
Enable Tag archiving and add <div id="trend"></div> and <p id="trend-status"></p>. This displays minute averages for the last hour as a table; pass the same points to your chart component to draw a curve.
Expected result No archive produces empty data. Keep gaps for bad-quality points using null. effectiveInterval reports the actual interval.
Open an equipment popup
Save a template in Popup Templates, add <button id="open-popup">Open equipment</button>, then bind its click. Replace the device, template and declared Tag codes.
Expected result The template defines displayed values, controls, alarms and trends. Dispatching the popup is not a write receipt; verify the visible popup and target values.
Navigate to another page
Choose one call for your button click handler. Relative paths start from the current screen; parent, child and other folders are allowed within the assets root.
JavaScriptJavaScript
// Use one of these calls in your button's click handler:api.navigation.gotoPage("details/equipment.html"); // Child pageapi.navigation.gotoPage("../overview.html"); // Parent pageapi.navigation.gotoPage("/assets/<folder>/index.html"); // Another folderapi.navigation.openUrl("https://<server-host>/manual", { openInNewWindow: true });
Follow the system language
The top-bar LANG control already switches languages. Give your title id="title", read the current language and subscribe to changes.
JavaScriptJavaScript
function renderText() { const zh = api.language.current().startsWith("zh"); document.getElementById("title").textContent = zh ? "设备总览" : "Equipment overview";}renderText();const stopLanguage = api.language.onChange(renderText);// Call stopLanguage() when this view is removed.
Use the same API in Vue
In Vue 3, add layout and Tag declarations to index.html, then save and mount this complete read-only component. Obtain api in onMounted. Runtime loads the SDK after publishing.
Expected result Set Vite base: "./" and upload dist contents with their folder structure. On unmount, cancel only component subscriptions; do not call api.destroy(). Here api is local to onMounted; retain it in component scope for buttons, as in the full Vue write example.
For development and acceptance, provide actual Tag codes and types, allowed write values, required page behavior, and the target runtime menu. The entry HTML declarations must match the page code.
List the Tag, alarm, and history scopes. For each write target, specify account permission, control access, and the equipment's allowed values.
Open the page from the runtime menu and check SDK initialization, GOOD quality, system LANG changes, and subscription cleanup on component unmount.
Check write receipts against subsequent normal collected values. Preserve command identity for uncertain outcomes and reconcile before the next operation.
Complete missing codes, types, or authorization scopes before publishing.