---
updatedAt: 2026-09-18T07:52:21.000Z
agentTools:
  projectIndex: https://docs.sixfab.com/llms.txt
---

# Deploying ThingsBoard

Send telemetry from ALPON X5 AI or ALPON X4 to ThingsBoard through ALPON Cloud: create the ThingsBoard MQTT integration and topic filter, build a lightweight MQTT client container, push it to the Sixfab Container Registry, and verify the data in ThingsBoard.

<HTMLBlock>{`
<style>
/* ══════════════════════════════════════════════════════════════════════════
   SIXFAB DOCS · ALPON TUTORIAL STYLESHEET (canonical, shared by every page
   under ALPON › Tutorials). Do not edit per page: change it here and re-stamp
   into all tutorials so the block stays byte-identical.
   Components: hero · meta · pill · aeo · toc · step-list · terminal · callout
   · spec-card · figure/lightbox · issue · stack · path · table · related guides.
   Page-specific components go AFTER the "END CANONICAL" marker.
   ══════════════════════════════════════════════════════════════════════════ */
/* ════════════════════════════════════════════════════════════════════════
   FONTS - Gilroy (5 weights) + JetBrains Mono (2 weights)
   Per design language §1.1 starter boilerplate.
═════════════════════════════════════════════════════════════════════════ */
@font-face { font-family:'Gilroy'; src:url('https://sixfab.com/wp-content/fonts/Gilroy-Regular.woff2')   format('woff2'); font-weight:400; font-display:swap; }
@font-face { font-family:'Gilroy'; src:url('https://sixfab.com/wp-content/fonts/Gilroy-Medium.woff2')    format('woff2'); font-weight:500; font-display:swap; }
@font-face { font-family:'Gilroy'; src:url('https://sixfab.com/wp-content/fonts/Gilroy-SemiBold.woff2')  format('woff2'); font-weight:600; font-display:swap; }
@font-face { font-family:'Gilroy'; src:url('https://sixfab.com/wp-content/fonts/Gilroy-Bold.woff2')      format('woff2'); font-weight:700; font-display:swap; }
@font-face { font-family:'Gilroy'; src:url('https://sixfab.com/wp-content/fonts/Gilroy-ExtraBold.woff2') format('woff2'); font-weight:800; font-display:swap; }
@font-face { font-family:'JetBrains Mono'; src:url('https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono@2.304/fonts/webfonts/JetBrainsMono-Regular.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:'JetBrains Mono'; src:url('https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono@2.304/fonts/webfonts/JetBrainsMono-Medium.woff2') format('woff2'); font-weight:500; font-style:normal; font-display:swap; }

/* ════════════════════════════════════════════════════════════════════════
   DESIGN TOKENS - six-tier system, scoped to .sf-doc
═════════════════════════════════════════════════════════════════════════ */
.sf-doc {
  --primary:       #034860;
  --secondary:     #00E0B8;
  --tertiary:      #1B2D45;
  --neutral:       #E8F5F0;
  --white:         #FFFFFF;
  --light:         #F6F8F9;
  --line:          #DDE6EC;
  --slate-light:   #94A8B5;
  --slate:         #52667A;
  --deep-ink:      #10202E;
  --ai-iris:       #6B47F0;
  --ai-mist:       #F0EDFF;
  --alpon-purple:  #4F008E;
  --alpon-cyan:    #00A6C8;   /* ALPON Gradient end */
  --alpon-cyan-deep: #007A8F; /* cyan surface for white text (WCAG AA 5.0:1) */
  --success:       #00B894;
  --warning:       #F59E0B;
  --danger:        #DC2626;
  --info:          #429CBF;
  --success-text:  #047857;
  --warning-text:  #92400E;
  --danger-text:   #B91C1C;
  --info-text:     #0E4A66;
  --success-bg:    #E0F5EE;
  --warning-bg:    #FDF1DC;
  --danger-bg:     #FBE5E5;
  --info-bg:       #DCEFF7;
  --on-primary:    #FFFFFF;

  --xs:   4px;  --sm:   8px;  --md:  16px;  --lg:  24px;
  --xl:  32px;  --2xl: 48px;  --3xl: 64px;

  --r-sm: 4px; --r-md: 6px; --r-lg: 8px; --r-xl: 12px; --r-2xl: 16px; --r-full: 9999px;

  --shadow-sm: 0 1px 2px rgba(10,23,33,.04);
  --shadow-md: 0 4px 12px rgba(10,23,33,.06);
  --shadow-lg: 0 8px 24px rgba(10,23,33,.08);

  --font-sans: 'Gilroy', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace;

  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--deep-ink);
  -webkit-font-smoothing: antialiased;
}
.sf-doc * { box-sizing: border-box; }

/* ════════════════════════════════════════════════════════════════════════
   BASE TYPOGRAPHY
═════════════════════════════════════════════════════════════════════════ */
.sf-doc h1 {
  font-size: 3rem; font-weight: 800; letter-spacing: -0.03em;
  line-height: 1.08; color: var(--deep-ink); margin: 0 0 16px;
}
.sf-doc h2 {
  font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em;
  line-height: 1.2; color: var(--primary);
  margin: 56px 0 16px; padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.sf-doc h2:first-of-type { margin-top: 0; }
.sf-doc h3 {
  font-size: 1.125rem; font-weight: 700; letter-spacing: -0.015em;
  line-height: 1.3; color: var(--deep-ink); margin: 28px 0 10px;
}
.sf-doc h4 {
  font-size: 0.875rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--slate);
  margin: 18px 0 6px;
}
.sf-doc p {
  font-size: 1rem; font-weight: 400; line-height: 1.6;
  color: var(--deep-ink); margin: 0 0 14px;
}
.sf-doc ul, .sf-doc ol { padding-left: 24px; margin: 8px 0 16px; }
.sf-doc li { font-size: 1rem; line-height: 1.6; color: var(--deep-ink); margin-bottom: 6px; }
.sf-doc ul li::marker { color: var(--primary); }
.sf-doc a { color: var(--primary); text-decoration: none; }
.sf-doc a:hover { color: var(--deep-ink); text-decoration: underline; }
.sf-doc code {
  font-family: var(--font-mono); font-size: 0.875rem;
  background: var(--light); color: var(--primary);
  padding: 1px 5px; border-radius: var(--r-sm); border: 0;
}
.sf-doc strong { color: var(--deep-ink); font-weight: 700; }
.sf-doc hr { border: 0; height: 1px; background: var(--line); margin: 48px 0; }

/* ════════════════════════════════════════════════════════════════════════
   META BAR
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  font-family: var(--font-mono); font-size: 0.75rem;
  color: var(--slate); margin: 0 0 24px;
}
.sf-doc .sf-meta__badge {
  font-family: var(--font-sans); font-weight: 700; font-size: 0.75rem;
  padding: 3px 8px; border-radius: var(--r-sm);
  background: var(--light); color: var(--primary);
  border: 1px solid var(--line); letter-spacing: 0;
  text-decoration: none !important;
}
.sf-doc .sf-meta__badge:hover { background: var(--neutral); color: var(--primary); }
.sf-doc .sf-meta__badge--mint {
  background: var(--neutral); color: var(--primary); border-color: var(--neutral);
}
.sf-doc .sf-meta__sep { color: var(--line); }

/* ════════════════════════════════════════════════════════════════════════
   HERO - compact, default Tier 1 surface
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-hero {
  padding: var(--xl); margin: 0 0 24px;
  background: var(--light); border: 1px solid var(--line);
  border-radius: var(--r-2xl);
}
.sf-doc .sf-hero__copy { min-width: 0; }
.sf-doc .sf-hero p.sf-hero__title,
.sf-doc .sf-hero .sf-hero__title {
  font-family: var(--font-sans);
  font-size: 2.5rem; font-weight: 800; line-height: 1.08;
  letter-spacing: -0.03em; color: var(--deep-ink); margin: 0 0 14px;
}
.sf-doc .sf-hero p.sf-hero__lead,
.sf-doc .sf-hero .sf-hero__lead {
  font-size: 1.0625rem; line-height: 1.6;
  color: var(--deep-ink); margin: 0 0 18px;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.sf-doc .sf-hero__chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* ════════════════════════════════════════════════════════════════════════
   PILLS
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-pill {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-sans); font-size: 0.75rem; font-weight: 600;
  padding: 4px 10px; border-radius: var(--r-sm);
  background: var(--light); color: var(--deep-ink);
  border: 1px solid var(--line); white-space: nowrap;
  vertical-align: middle; line-height: 1.4;
}
.sf-doc .sf-pill--alpon-x5 {
  background: var(--alpon-purple); color: #FFFFFF !important; border-color: var(--alpon-purple);
}
.sf-doc .sf-pill--alpon-x4 {
  background: var(--alpon-cyan-deep); color: #FFFFFF !important; border-color: var(--alpon-cyan-deep);
}
.sf-doc .sf-pill--success { background: var(--success-bg); color: var(--success-text); border-color: var(--success-bg); }
.sf-doc .sf-pill--info    { background: var(--info-bg);    color: var(--info-text);    border-color: var(--info-bg); }
.sf-doc .sf-pill--warning { background: var(--warning-bg); color: var(--warning-text); border-color: var(--warning-bg); }

/* ════════════════════════════════════════════════════════════════════════
   AEO ANSWER BLOCK - default Tier 1
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-aeo {
  position: relative;
  background: var(--light);
  border: 1px solid var(--line);
  border-left: 4px solid var(--primary);
  border-radius: var(--r-md);
  padding: var(--lg) var(--xl);
  margin: 0 0 var(--xl);
}
.sf-doc .sf-aeo__label {
  display: block; font-family: var(--font-sans);
  font-size: 1.375rem; font-weight: 700;
  line-height: 1.25; letter-spacing: -0.015em;
  text-transform: none; color: var(--primary);
  margin: 0 0 var(--sm);
}
.sf-doc .sf-aeo__text {
  font-size: 1rem;
  line-height: 1.6;
  color: var(--deep-ink);
  margin: 0;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.sf-doc .sf-aeo__text strong { color: var(--primary); font-weight: 600; }
.sf-doc .sf-aeo__text code { font-size: 0.8125rem; }

/* ════════════════════════════════════════════════════════════════════════
   IN THIS GUIDE - sf-toc
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-toc {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  padding: var(--md) var(--lg);
  background: var(--light); border: 1px solid var(--line);
  border-radius: var(--r-lg); margin: 0 0 var(--xl);
}
.sf-doc .sf-toc__label {
  font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--slate); margin-right: var(--sm);
}
.sf-doc .sf-toc__item {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; background: var(--white);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: 0.8125rem; font-weight: 600;
  color: var(--deep-ink) !important; text-decoration: none !important;
  transition: border-color .15s, box-shadow .15s; white-space: nowrap;
}
.sf-doc .sf-toc__item:hover,
.sf-doc .sf-toc__item:focus {
  background: var(--primary); color: var(--white) !important;
  border-color: var(--primary); text-decoration: none !important;
}
.sf-doc .sf-toc__item:hover .sf-toc__num,
.sf-doc .sf-toc__item:focus .sf-toc__num { color: var(--secondary); }
.sf-doc .sf-toc__num {
  font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 500;
  color: var(--slate);
}

/* ════════════════════════════════════════════════════════════════════════
   ICONS
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-icon { width: 16px; height: 16px; flex-shrink: 0; vertical-align: -2px; }
.sf-doc .sf-icon--stroke { fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }

/* ════════════════════════════════════════════════════════════════════════
   SPEC CARDS - identical to alpon-x4-specifications.html tables
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-spec-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px; margin: 0 0 24px;
}
.sf-doc .sf-spec-card {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-xl); padding: 20px 22px;
  display: flex; flex-direction: column;
  margin: 16px 0 24px; transition: border-color .15s;
}
.sf-doc .sf-spec-grid .sf-spec-card { margin: 0; }
.sf-doc .sf-spec-card:hover { border-color: var(--slate-light); }
.sf-doc .sf-spec-card__head {
  display: flex; align-items: center; gap: 10px;
  padding-bottom: 14px; border-bottom: 1px solid var(--line);
  margin-bottom: 14px;
}
.sf-doc .sf-spec-card__icon {
  width: 32px; height: 32px; border-radius: var(--r-md);
  background: var(--light); color: var(--primary);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.sf-doc .sf-spec-card__icon svg { width: 18px; height: 18px; }
.sf-doc .sf-spec-card__title {
  font-size: 1rem; font-weight: 700;
  color: var(--primary); letter-spacing: -0.01em;
}
.sf-doc .sf-spec-card__body { display: flex; flex-direction: column; }
.sf-doc .sf-spec-row {
  display: grid; grid-template-columns: minmax(160px, 30%) 1fr;
  gap: 24px; align-items: baseline;
  padding: 11px 0; border-bottom: 1px dashed var(--line);
}
.sf-doc .sf-spec-row:first-child { padding-top: 4px; }
.sf-doc .sf-spec-row:last-child { border-bottom: 0; padding-bottom: 4px; }
.sf-doc .sf-spec-row__key {
  font-size: 0.9375rem; font-weight: 700;
  color: var(--deep-ink); line-height: 1.5;
}
.sf-doc .sf-spec-row__val {
  font-size: 0.9375rem; font-weight: 500;
  color: var(--deep-ink); line-height: 1.55;
  text-align: left; min-width: 0;
}
.sf-doc .sf-spec-row__val code { font-size: 0.875rem; }
.sf-doc .sf-spec-row__val em { font-style: italic; color: var(--slate); font-weight: 500; }

/* ════════════════════════════════════════════════════════════════════════
   CALLOUT
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-callout {
  display: flex; flex-direction: column; gap: 6px;
  border-radius: var(--r-md); padding: 14px 18px;
  margin: 20px 0; border-left: 4px solid;
}
.sf-doc .sf-callout__header {
  display: flex; align-items: center; gap: 8px;
  font-size: 0.875rem; font-weight: 700; line-height: 1;
}
.sf-doc .sf-callout__header svg { width: 16px; height: 16px; flex-shrink: 0; }
.sf-doc .sf-callout__content { font-size: 0.9375rem; line-height: 1.6; color: var(--deep-ink); }
.sf-doc .sf-callout__content p { margin: 0 0 6px; font-size: 0.9375rem; color: inherit; }
.sf-doc .sf-callout__content p:last-child { margin-bottom: 0; }
.sf-doc .sf-callout__content code { background: rgba(0,0,0,0.06); border: 0; }
.sf-doc .sf-callout--info     { background: var(--info-bg);    border-left-color: var(--info); }
.sf-doc .sf-callout--info     .sf-callout__header { color: var(--info-text); }
.sf-doc .sf-callout--success  { background: var(--success-bg); border-left-color: var(--success); }
.sf-doc .sf-callout--success  .sf-callout__header { color: var(--success-text); }
.sf-doc .sf-callout--warning  { background: var(--warning-bg); border-left-color: var(--warning); }
.sf-doc .sf-callout--warning  .sf-callout__header { color: var(--warning-text); }
.sf-doc .sf-callout--danger   { background: var(--danger-bg);  border-left-color: var(--danger); }
.sf-doc .sf-callout--danger   .sf-callout__header { color: var(--danger-text); }

/* ════════════════════════════════════════════════════════════════════════
   STEP LIST
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-step-list {
  position: relative; padding: 0;
  margin: var(--lg) 0 var(--xl);
  list-style: none !important;
}
.sf-doc .sf-step-list::before {
  content: ''; position: absolute;
  left: 23px; top: 48px; bottom: 24px;
  width: 2px; background: var(--line); z-index: 0;
}
.sf-doc .sf-step {
  position: relative; z-index: 1;
  padding-bottom: var(--2xl); scroll-margin-top: 24px;
}
.sf-doc .sf-step:last-child { padding-bottom: 0; }
.sf-doc .sf-step__header {
  display: grid; grid-template-columns: 48px 1fr;
  align-items: center; gap: 0 22px;
  margin-bottom: var(--md);
}
.sf-doc .sf-step__num {
  width: 48px; height: 48px;
  border-radius: var(--r-full);
  background: var(--primary); color: var(--on-primary);
  font-family: var(--font-sans); font-size: 1.0625rem; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 0 0 5px var(--white), 0 4px 10px rgba(10,23,33,.10);
  align-self: center; flex-shrink: 0;
}
.sf-doc .sf-step__title {
  font-family: var(--font-sans); font-size: 1.5rem; font-weight: 700;
  letter-spacing: -0.02em; color: var(--deep-ink);
  line-height: 1.15; margin: 0; padding: 0;
  align-self: center; display: flex; align-items: center;
  gap: 10px; flex-wrap: wrap;
}
.sf-doc .sf-step__title code { font-size: 1.125rem; }
.sf-doc .sf-step__body { padding-left: 70px; min-width: 0; }
.sf-doc .sf-step__body p { font-size: 1rem; line-height: 1.65; margin: 0 0 14px; }
.sf-doc .sf-step__body ul,
.sf-doc .sf-step__body ol { margin: 6px 0 14px; }
.sf-doc .sf-step__body ul li,
.sf-doc .sf-step__body ol li { font-size: 0.9375rem; margin-bottom: 4px; }

/* ════════════════════════════════════════════════════════════════════════
   TERMINAL
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-terminal {
  background: #0d1117 !important;
  border: 1px solid #30363d;
  border-radius: var(--r-lg);
  margin: 14px 0 18px;
  overflow: hidden; box-shadow: var(--shadow-md);
}
.sf-doc .sf-terminal__header {
  display: flex !important; align-items: center; gap: 6px;
  padding: 10px 14px; background: #161b22 !important;
  border-bottom: 1px solid #30363d;
}
.sf-doc .sf-terminal__dot {
  width: 11px; height: 11px;
  border-radius: var(--r-full); flex-shrink: 0;
}
.sf-doc .sf-terminal__title {
  margin-left: 8px; font-family: var(--font-mono) !important;
  font-size: 0.75rem !important; color: #8B949E !important; font-weight: 500;
}
.sf-doc .sf-terminal__body { padding: 14px 16px; overflow-x: auto; }
.sf-doc .sf-terminal__body pre {
  margin: 0 !important; padding: 0 !important;
  background: transparent !important; border: 0 !important;
  font-family: var(--font-mono) !important;
  font-size: 0.825rem !important; line-height: 1.65 !important;
  color: #e6edf3 !important; white-space: pre;
}
.sf-doc .t-dim   { color: #8B949E !important; }
.sf-doc .t-green { color: #56d364 !important; font-weight: 600; }
.sf-doc .t-blue  { color: #79c0ff !important; }
.sf-doc .t-yel   { color: #e3b341 !important; }
.sf-doc .t-pp    { color: #d2a8ff !important; }
.sf-doc .t-red   { color: #ff7b72 !important; }
.sf-doc .t-hl    { color: #56d364 !important; font-weight: 600; }

/* ════════════════════════════════════════════════════════════════════════
   COMPARISON GRID - Stripe-style two-column path picker
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-paths {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px;
  margin: 16px 0 32px;
}
.sf-doc .sf-path {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-xl); padding: 22px 24px;
  display: flex; flex-direction: column;
  transition: border-color .15s, box-shadow .15s;
}
.sf-doc .sf-path:hover { border-color: var(--slate-light); box-shadow: var(--shadow-md); }
.sf-doc .sf-path__tag {
  font-family: var(--font-mono); font-size: 0.6875rem;
  font-weight: 500; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--slate);
  margin-bottom: 8px;
}
.sf-doc .sf-path__title {
  font-size: 1.125rem; font-weight: 700;
  color: var(--deep-ink); margin: 0 0 8px;
  letter-spacing: -0.01em;
}
.sf-doc .sf-path__desc {
  font-size: 0.9375rem; line-height: 1.55;
  color: var(--slate); margin: 0 0 14px;
}
.sf-doc .sf-path__list {
  list-style: none !important;
  padding: 0 !important;
  margin: 0 0 14px !important;
}
.sf-doc .sf-path__list li {
  font-size: 0.9375rem;
  color: var(--deep-ink);
  padding: 6px 0 6px 28px;
  position: relative;
  margin: 0;
  line-height: 1.5;
  list-style: none !important;
}
.sf-doc .sf-path__list li::marker { content: '' !important; }
.sf-doc .sf-path__list li::before {
  content: ''; position: absolute;
  left: 0; top: 10px;
  width: 16px; height: 16px;
  background: var(--neutral);
  border-radius: var(--r-full);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23034860' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 11px;
  flex-shrink: 0;
}
.sf-doc .sf-path__foot {
  margin-top: auto; padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: 0.75rem;
  color: var(--slate);
}
.sf-doc .sf-path__foot strong { color: var(--primary); font-weight: 600; }

/* ════════════════════════════════════════════════════════════════════════
   DOCKERFILE STACK PICKER
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-stack-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px; margin: 16px 0 24px;
}
.sf-doc .sf-stack {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 18px 20px;
  text-decoration: none !important;
  transition: border-color .15s, transform .15s, box-shadow .15s;
  display: flex; align-items: center; gap: 14px;
  color: var(--deep-ink) !important;
}
.sf-doc .sf-stack__badge {
  width: 44px; height: 44px;
  border-radius: var(--r-md);
  background: var(--neutral);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono);
  font-size: 1rem; font-weight: 700;
  letter-spacing: -0.02em; flex-shrink: 0;
}
.sf-doc .sf-stack__copy { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sf-doc .sf-stack:hover {
  border-color: var(--primary); transform: translateY(-2px);
  box-shadow: var(--shadow-md); text-decoration: none !important;
}
.sf-doc .sf-stack__lang {
  font-family: var(--font-sans); font-size: 0.9375rem;
  font-weight: 700; color: var(--deep-ink); letter-spacing: -0.01em;
}
.sf-doc .sf-stack__base {
  font-family: var(--font-mono); font-size: 0.75rem;
  color: var(--slate); font-weight: 500;
}

/* ════════════════════════════════════════════════════════════════════════
   FIGURE & LIGHTBOX
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-figure {
  margin: 16px 0; border-radius: var(--r-lg);
  overflow: hidden; border: 1px solid var(--line);
  background: var(--white);
}
.sf-doc .sf-figure a {
  display: block; cursor: zoom-in;
  text-decoration: none !important;
}
.sf-doc .sf-figure img {
  width: 100%; height: auto; display: block;
  transition: opacity .15s;
}
.sf-doc .sf-figure a:hover img { opacity: 0.94; }
.sf-doc .sf-figure figcaption {
  font-family: var(--font-sans);
  font-size: 0.8125rem; color: var(--slate);
  padding: 10px 14px; background: var(--light);
  border-top: 1px solid var(--line);
  line-height: 1.5; font-style: italic;
}
.sf-doc .sf-fig-anchor {
  display: block; position: relative;
  top: -80px; visibility: hidden;
}
.sf-doc .sf-lightbox {
  display: none; position: fixed; inset: 0;
  z-index: 9999; background: rgba(10,23,33,0.92);
  align-items: center; justify-content: center; padding: 24px;
}
.sf-doc .sf-lightbox:target { display: flex; }
.sf-doc .sf-lightbox__backdrop {
  position: absolute; inset: 0; cursor: zoom-out;
}
.sf-doc .sf-lightbox__close {
  position: absolute; top: 18px; right: 18px;
  width: 36px; height: 36px;
  background: rgba(255,255,255,0.12);
  color: #fff !important;
  border: 1px solid rgba(255,255,255,0.25);
  border-radius: var(--r-full);
  display: flex; align-items: center; justify-content: center;
  z-index: 2; text-decoration: none !important;
  transition: background .15s, transform .15s;
}
.sf-doc .sf-lightbox__close:hover {
  background: rgba(255,255,255,0.22); transform: rotate(90deg);
}
.sf-doc .sf-lightbox__close svg {
  width: 18px; height: 18px;
  stroke: #fff; stroke-width: 2.2; fill: none;
}
.sf-doc .sf-lightbox__inner {
  position: relative; z-index: 1;
  max-width: 1200px; width: 100%;
  display: flex; flex-direction: column; align-items: center;
}
.sf-doc .sf-lightbox__img-wrap {
  display: block; cursor: zoom-out;
  text-decoration: none !important; max-width: 100%;
}
.sf-doc .sf-lightbox__img-wrap img {
  display: block; max-width: 100%;
  max-height: 78vh; height: auto;
  border-radius: var(--r-md);
  border: 1px solid rgba(255,255,255,0.12);
}
.sf-doc .sf-lightbox__caption {
  margin-top: 14px;
  color: rgba(255,255,255,0.85);
  font-size: 0.875rem;
  font-family: var(--font-sans);
  text-align: center; max-width: 700px; line-height: 1.5;
}

/* ════════════════════════════════════════════════════════════════════════
   ISSUE / TROUBLESHOOTING - mirrors alpon-create-wifi-hotspot pattern
   summary + tag pill + Symptom/Cause/Fix body
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-issue {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  margin: 0 0 12px;
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s;
}
.sf-doc .sf-issue:hover { border-color: var(--slate-light); }
.sf-doc .sf-issue[open] {
  border-color: var(--primary);
  box-shadow: var(--shadow-sm);
}
.sf-doc .sf-issue__summary {
  display: flex; align-items: center; gap: 12px;
  padding: 16px 20px;
  font-family: var(--font-sans);
  font-size: 1rem; font-weight: 700;
  color: var(--deep-ink);
  cursor: pointer; list-style: none;
}
.sf-doc .sf-issue__summary::-webkit-details-marker { display: none; }
.sf-doc .sf-issue__summary > span:nth-child(2) {
  flex: 1; line-height: 1.45; font-weight: 700;
}
.sf-doc .sf-issue__tag {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 4px 9px;
  border-radius: var(--r-sm);
  background: var(--info-bg);
  color: var(--info-text);
  border: 1px solid var(--info-bg);
  flex-shrink: 0;
  white-space: nowrap;
}
.sf-doc .sf-issue__tag--hw {
  background: var(--danger-bg); color: var(--danger-text); border-color: var(--danger-bg);
}
.sf-doc .sf-issue__tag--sw {
  background: var(--ai-mist); color: var(--ai-iris); border-color: var(--ai-mist);
}
.sf-doc .sf-issue__tag--auth {
  background: var(--warning-bg); color: var(--warning-text); border-color: var(--warning-bg);
}
.sf-doc .sf-issue__tag--net {
  background: var(--info-bg); color: var(--info-text); border-color: var(--info-bg);
}
.sf-doc .sf-issue__tag--config {
  background: var(--neutral); color: var(--primary); border-color: var(--neutral);
}
.sf-doc .sf-issue__chev {
  width: 18px; height: 18px;
  color: var(--slate);
  flex-shrink: 0;
  transition: transform .2s;
}
.sf-doc .sf-issue[open] .sf-issue__chev {
  transform: rotate(180deg);
  color: var(--primary);
}
.sf-doc .sf-issue__body {
  padding: 4px 20px 20px;
  border-top: 1px solid var(--line);
}
.sf-doc .sf-issue__body h4 {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--slate);
  margin: 18px 0 8px;
}
.sf-doc .sf-issue__body h4:first-child { margin-top: 14px; }
.sf-doc .sf-issue__body p {
  font-size: 0.9375rem;
  line-height: 1.65;
  margin: 0 0 8px;
  color: var(--deep-ink);
}
.sf-doc .sf-issue__body p:last-child { margin-bottom: 0; }
.sf-doc .sf-issue__body code { font-size: 0.8125rem; }
.sf-doc .sf-issue__body .sf-terminal { margin: 10px 0 0; }

/* ════════════════════════════════════════════════════════════════════════
   DARK MODE
═════════════════════════════════════════════════════════════════════════ */
[data-color-mode="dark"] .sf-doc {
  --primary: #034860; --secondary: #00E0B8; --tertiary: #1B2D45;
  --neutral: #E8F5F0; --white: #FFFFFF; --light: #14222F;
  --line: #2A3A4D; --slate-light: #94A8B5; --slate: #B5C3CE;
  --deep-ink: #E8F5F0;
  --success-bg: #052E1B; --warning-bg: #2A1F05;
  --danger-bg: #2A0E0E; --info-bg: #0A2E3F;
  --success-text: #34D399; --warning-text: #FBBF24;
  --danger-text: #F87171; --info-text: #5CD3EE;
  --ai-iris: #B59CFF; --ai-mist: #1F1A33;
  color: var(--deep-ink);
}
[data-color-mode="dark"] .sf-doc h1,
[data-color-mode="dark"] .sf-doc h3,
[data-color-mode="dark"] .sf-doc h4,
[data-color-mode="dark"] .sf-doc strong { color: #FFFFFF; }
[data-color-mode="dark"] .sf-doc h2 { color: var(--secondary); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc p,
[data-color-mode="dark"] .sf-doc li,
[data-color-mode="dark"] .sf-doc .sf-aeo__text,
[data-color-mode="dark"] .sf-doc .sf-callout__content { color: var(--neutral); }
html[data-color-mode="dark"] .sf-doc a { color: var(--secondary); }
[data-color-mode="dark"] .sf-doc code { background: rgba(255,255,255,0.06); color: var(--secondary); }
[data-color-mode="dark"] .sf-doc hr { background: var(--line); }
[data-color-mode="dark"] .sf-doc ul li::marker { color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-meta__badge { background: rgba(255,255,255,0.06); color: var(--secondary); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-aeo { background: rgba(255,255,255,0.04); border-color: var(--line); border-left-color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-aeo__label { color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-aeo__text strong { color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-hero { background: rgba(255,255,255,0.04); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-hero p.sf-hero__title,
[data-color-mode="dark"] .sf-doc .sf-hero .sf-hero__title { color: #FFFFFF; }
[data-color-mode="dark"] .sf-doc .sf-hero p.sf-hero__lead,
[data-color-mode="dark"] .sf-doc .sf-hero .sf-hero__lead { color: var(--neutral); }
[data-color-mode="dark"] .sf-doc .sf-toc { background: rgba(255,255,255,0.04); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-toc__item { background: transparent; color: var(--neutral) !important; border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-toc__item:hover { background: var(--secondary); color: var(--tertiary) !important; border-color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-toc__item:hover .sf-toc__num { color: var(--tertiary); }
[data-color-mode="dark"] .sf-doc .sf-spec-card { background: rgba(255,255,255,0.04); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-spec-card:hover { border-color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-spec-card__head { border-bottom-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-spec-card__icon { background: rgba(0,224,184,0.10); color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-spec-card__title { color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-spec-row { border-bottom-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-spec-row__key { color: #FFFFFF; }
[data-color-mode="dark"] .sf-doc .sf-spec-row__val { color: var(--neutral); }
[data-color-mode="dark"] .sf-doc .sf-spec-row__val code { background: rgba(255,255,255,0.06); color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-pill { background: rgba(255,255,255,0.06); color: var(--neutral); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-path { background: rgba(255,255,255,0.04); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-path__list li { color: var(--neutral); }
[data-color-mode="dark"] .sf-doc .sf-path__list li::before { background: rgba(0,224,184,0.14); background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300E0B8' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>"); }
[data-color-mode="dark"] .sf-doc .sf-path__foot { border-top-color: var(--line); color: var(--slate); }
[data-color-mode="dark"] .sf-doc .sf-path__foot strong { color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-stack { background: rgba(255,255,255,0.04); border-color: var(--line); color: var(--neutral) !important; }
[data-color-mode="dark"] .sf-doc .sf-stack:hover { border-color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-stack__lang { color: #FFFFFF; }
[data-color-mode="dark"] .sf-doc .sf-stack__base { color: var(--slate); }
[data-color-mode="dark"] .sf-doc .sf-stack__badge { background: rgba(0,224,184,0.12); color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-issue { background: rgba(255,255,255,0.04); border-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-issue:hover { border-color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-issue[open] { border-color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-issue__summary { color: #FFFFFF; }
[data-color-mode="dark"] .sf-doc .sf-issue__body { border-top-color: var(--line); }
[data-color-mode="dark"] .sf-doc .sf-issue__body p { color: var(--neutral); }
[data-color-mode="dark"] .sf-doc .sf-issue__body code { background: rgba(255,255,255,0.06); color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-issue__tag--sw { background: rgba(107,71,240,0.18); color: #B59CFF; border-color: rgba(107,71,240,0.30); }
[data-color-mode="dark"] .sf-doc .sf-issue__tag--config { background: rgba(0,224,184,0.12); color: var(--secondary); border-color: rgba(0,224,184,0.22); }
[data-color-mode="dark"] .sf-doc .sf-issue[open] .sf-issue__chev { color: var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-step__num { box-shadow: 0 0 0 5px var(--tertiary), 0 4px 10px rgba(0,0,0,.40); }

@media (prefers-color-scheme: dark) {
  html:not([data-color-mode="light"]) .sf-doc {
    --primary: #034860; --secondary: #00E0B8; --tertiary: #1B2D45;
    --neutral: #E8F5F0; --white: #FFFFFF; --light: #14222F;
    --line: #2A3A4D; --slate-light: #94A8B5; --slate: #B5C3CE;
    --deep-ink: #E8F5F0;
    --success-bg: #052E1B; --warning-bg: #2A1F05;
    --danger-bg: #2A0E0E; --info-bg: #0A2E3F;
    --success-text: #34D399; --warning-text: #FBBF24;
    --danger-text: #F87171; --info-text: #5CD3EE;
  --ai-iris: #B59CFF; --ai-mist: #1F1A33;
    color: var(--deep-ink);
  }
  html:not([data-color-mode="light"]) .sf-doc h1,
  html:not([data-color-mode="light"]) .sf-doc h3,
  html:not([data-color-mode="light"]) .sf-doc h4,
  html:not([data-color-mode="light"]) .sf-doc strong { color: #FFFFFF; }
  html:not([data-color-mode="light"]) .sf-doc h2 { color: var(--secondary); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc p,
  html:not([data-color-mode="light"]) .sf-doc li,
  html:not([data-color-mode="light"]) .sf-doc .sf-aeo__text,
  html:not([data-color-mode="light"]) .sf-doc .sf-callout__content { color: var(--neutral); }
  html:not([data-color-mode="light"]) .sf-doc a { color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc code { background: rgba(255,255,255,0.06); color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc hr { background: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc ul li::marker { color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-meta__badge { background: rgba(255,255,255,0.06); color: var(--secondary); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-aeo { background: rgba(255,255,255,0.04); border-color: var(--line); border-left-color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-aeo__label { color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-aeo__text strong { color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-hero { background: rgba(255,255,255,0.04); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-hero p.sf-hero__title,
  html:not([data-color-mode="light"]) .sf-doc .sf-hero .sf-hero__title { color: #FFFFFF; }
  html:not([data-color-mode="light"]) .sf-doc .sf-hero p.sf-hero__lead,
  html:not([data-color-mode="light"]) .sf-doc .sf-hero .sf-hero__lead { color: var(--neutral); }
  html:not([data-color-mode="light"]) .sf-doc .sf-toc { background: rgba(255,255,255,0.04); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-toc__item { background: transparent; color: var(--neutral) !important; border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-toc__item:hover { background: var(--secondary); color: var(--tertiary) !important; border-color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-toc__item:hover .sf-toc__num { color: var(--tertiary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-card { background: rgba(255,255,255,0.04); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-card:hover { border-color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-card__head { border-bottom-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-card__icon { background: rgba(0,224,184,0.10); color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-card__title { color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-row { border-bottom-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-row__key { color: #FFFFFF; }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-row__val { color: var(--neutral); }
  html:not([data-color-mode="light"]) .sf-doc .sf-spec-row__val code { background: rgba(255,255,255,0.06); color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-pill { background: rgba(255,255,255,0.06); color: var(--neutral); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-path { background: rgba(255,255,255,0.04); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-path__list li { color: var(--neutral); }
  html:not([data-color-mode="light"]) .sf-doc .sf-path__list li::before { background: rgba(0,224,184,0.14); background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300E0B8' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>"); }
  html:not([data-color-mode="light"]) .sf-doc .sf-path__foot { border-top-color: var(--line); color: var(--slate); }
  html:not([data-color-mode="light"]) .sf-doc .sf-path__foot strong { color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-stack { background: rgba(255,255,255,0.04); border-color: var(--line); color: var(--neutral) !important; }
  html:not([data-color-mode="light"]) .sf-doc .sf-stack:hover { border-color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-stack__lang { color: #FFFFFF; }
  html:not([data-color-mode="light"]) .sf-doc .sf-stack__base { color: var(--slate); }
  html:not([data-color-mode="light"]) .sf-doc .sf-stack__badge { background: rgba(0,224,184,0.12); color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue { background: rgba(255,255,255,0.04); border-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue:hover { border-color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue[open] { border-color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue__summary { color: #FFFFFF; }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue__body { border-top-color: var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue__body p { color: var(--neutral); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue__body code { background: rgba(255,255,255,0.06); color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue__tag--sw { background: rgba(107,71,240,0.18); color: #B59CFF; border-color: rgba(107,71,240,0.30); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue__tag--config { background: rgba(0,224,184,0.12); color: var(--secondary); border-color: rgba(0,224,184,0.22); }
  html:not([data-color-mode="light"]) .sf-doc .sf-issue[open] .sf-issue__chev { color: var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-step__num { box-shadow: 0 0 0 5px var(--tertiary), 0 4px 10px rgba(0,0,0,.40); }
}

/* ════════════════════════════════════════════════════════════════════════
   RESPONSIVE
═════════════════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {
  .sf-doc h1 { font-size: 2.25rem; }
  .sf-doc h2 { font-size: 1.25rem; margin-top: 48px; }
  .sf-doc .sf-hero { padding: var(--md); }
  .sf-doc .sf-hero p.sf-hero__title,
  .sf-doc .sf-hero .sf-hero__title { font-size: 1.75rem; }
  .sf-doc .sf-aeo { padding: var(--md) var(--lg); }
  .sf-doc .sf-aeo__label { font-size: 1.125rem; }
  .sf-doc .sf-toc { gap: 4px; padding: 10px; }
  .sf-doc .sf-spec-card { padding: 16px 18px; }
  .sf-doc .sf-spec-row { grid-template-columns: 1fr; gap: 4px; padding: 12px 0; }
  .sf-doc .sf-spec-row__key { font-size: 0.875rem; }
  .sf-doc .sf-spec-row__val { font-size: 0.9375rem; }
  .sf-doc .sf-paths { grid-template-columns: 1fr; }
  .sf-doc .sf-stack-grid { grid-template-columns: 1fr; }
  .sf-doc .sf-step-list::before { left: 19px; top: 40px; }
  .sf-doc .sf-step__header { grid-template-columns: 40px 1fr; gap: 0 16px; }
  .sf-doc .sf-step__num { width: 40px; height: 40px; font-size: 0.9375rem; }
  .sf-doc .sf-step__title { font-size: 1.25rem; line-height: 1.2; }
  .sf-doc .sf-step__body { padding-left: 56px; }
}
@media (max-width: 480px) {
  .sf-doc .sf-hero p.sf-hero__title,
  .sf-doc .sf-hero .sf-hero__title { font-size: 1.5rem; }
  .sf-doc .sf-step__body { padding-left: 0; }
}

/* ═══════════════════════════════════════════════════════════════
   TABLES · .sf-table inside .sf-table-wrap (core component)
   Real <table> markup needs the ReadMe reset at the end of this
   section: ReadMe ships table { display:block; width:max-content }.
   ═══════════════════════════════════════════════════════════════ */
.sf-doc .sf-table-wrap { display:block; width:100%; overflow-x:auto; border:1px solid var(--line); border-radius:var(--r-lg); background:var(--white); margin:16px 0 24px; }
.sf-doc .sf-table { width:100% !important; border-collapse:separate; border-spacing:0; font-size:0.9375rem; margin:0 !important; }
.sf-doc .sf-table thead th { padding:12px 16px; font-family:var(--font-sans); font-size:0.8125rem; font-weight:700; letter-spacing:0; text-transform:none; color:var(--slate); background:var(--light); text-align:left; border-bottom:1px solid var(--line); white-space:nowrap; }
.sf-doc .sf-table td { padding:12px 16px; border-bottom:1px solid var(--line); font-size:0.9375rem; color:var(--deep-ink); vertical-align:top; }
.sf-doc .sf-table tbody th, .sf-doc .sf-table th[scope="row"] { padding:12px 16px; border-bottom:1px solid var(--line); font-family:var(--font-sans); font-size:0.9375rem; font-weight:600; text-align:left; color:var(--primary); background:var(--light); width:32%; vertical-align:top; white-space:normal; }
.sf-doc .sf-table tr:last-child td, .sf-doc .sf-table tr:last-child th { border-bottom:0; }
.sf-doc .sf-table code { font-size:0.8125rem; }
.sf-doc .sf-table--data { table-layout:fixed !important; width:100% !important; min-width:100% !important; }
.sf-doc .sf-table--data thead th { white-space:normal !important; }
.sf-doc .sf-table--data td:nth-child(1), .sf-doc .sf-table--data th:nth-child(1) { width:22% !important; }
.sf-doc .sf-table--data td:nth-child(2), .sf-doc .sf-table--data th:nth-child(2) { width:39% !important; }
.sf-doc .sf-table--data td:nth-child(3), .sf-doc .sf-table--data th:nth-child(3) { width:39% !important; }
.sf-doc .sf-table--data tbody tr td:first-child { font-weight:600; color:var(--primary); }
.sf-doc .sf-table-wrap { display:block !important; width:100% !important; overflow-x:auto !important; }

[data-color-mode="dark"] .sf-doc .sf-table-wrap { background:rgba(255,255,255,0.04); border-color:var(--line); }
[data-color-mode="dark"] .sf-doc .sf-table thead th { background:rgba(255,255,255,0.06); color:var(--slate); border-bottom-color:var(--line); }
[data-color-mode="dark"] .sf-doc .sf-table td { color:var(--neutral); border-bottom-color:var(--line); }
[data-color-mode="dark"] .sf-doc .sf-table tbody th, [data-color-mode="dark"] .sf-doc .sf-table th[scope="row"] { background:rgba(255,255,255,0.06); color:var(--secondary); border-bottom-color:var(--line); }
[data-color-mode="dark"] .sf-doc .sf-table--data tbody tr td:first-child { color:var(--secondary); }
@media (prefers-color-scheme: dark) {
  html:not([data-color-mode="light"]) .sf-doc .sf-table-wrap { background:rgba(255,255,255,0.04); border-color:var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-table thead th { background:rgba(255,255,255,0.06); color:var(--slate); border-bottom-color:var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-table td { color:var(--neutral); border-bottom-color:var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-table tbody th, html:not([data-color-mode="light"]) .sf-doc .sf-table th[scope="row"] { background:rgba(255,255,255,0.06); color:var(--secondary); border-bottom-color:var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-table--data tbody tr td:first-child { color:var(--secondary); }
}
@media (max-width: 640px) {
  .sf-doc .sf-table td, .sf-doc .sf-table th { padding:9px 12px; font-size:0.8125rem; }
}

/* ReadMe table reset */
.markdown-body table { margin-bottom:0 !important; }
.sf-doc table.sf-table { display:table !important; width:100% !important; table-layout:auto !important; }
.sf-doc table.sf-table.sf-table--data { table-layout:fixed !important; }
/* Modifiers used by several tutorials but missing from the base lineage */
.sf-doc .sf-step__hint { font-size: 0.875rem; color: var(--slate); margin: 6px 0 0; }
.sf-doc .sf-terminal__dot--r { background: #ff5f56; }
.sf-doc .sf-terminal__dot--y { background: #ffbd2e; }
.sf-doc .sf-terminal__dot--g { background: #27c93f; }
.sf-doc .sf-terminal__lang { margin-left: auto; font-family: var(--font-mono) !important; font-size: 0.6875rem !important; color: #c9d1d9 !important; background: rgba(255,255,255,0.06); padding: 2px 8px; border-radius: var(--r-sm); font-weight: 600; letter-spacing: 0.05em; }
[data-color-mode="dark"] .sf-doc .sf-step__hint { color: var(--slate); }
@media (prefers-color-scheme: dark) {
  html:not([data-color-mode="light"]) .sf-doc .sf-step__hint { color: var(--slate); }
}
/* ════════════════════════════════════════════════════════════════════════
   RELATED GUIDES — shared discovery footer
═════════════════════════════════════════════════════════════════════════ */
.sf-doc .sf-related { position:relative; margin:56px 0 8px; padding:28px; border:1px solid var(--line); border-radius:var(--r-2xl); background:linear-gradient(135deg, rgba(3,72,96,.055) 0%, rgba(0,224,184,.075) 100%); overflow:hidden; }
.sf-doc .sf-related::before { content:''; position:absolute; width:220px; height:220px; right:-90px; top:-120px; border-radius:50%; background:radial-gradient(circle, rgba(0,224,184,.18) 0%, rgba(0,224,184,0) 70%); pointer-events:none; }
.sf-doc .sf-related__head { position:relative; display:grid; grid-template-columns:minmax(0, .8fr) minmax(260px, 1.2fr); gap:24px; align-items:end; margin-bottom:22px; }
.sf-doc .sf-related__eyebrow { display:block; margin-bottom:7px; font-family:var(--font-mono); font-size:.6875rem; font-weight:500; line-height:1.4; letter-spacing:.13em; text-transform:uppercase; color:var(--primary); }
.sf-doc .sf-related__title { margin:0; padding:0; border:0; font-size:1.625rem; line-height:1.15; color:var(--deep-ink); }
.sf-doc .sf-related__intro { margin:0; color:var(--slate); font-size:.9375rem; line-height:1.55; }
.sf-doc .sf-related__grid { position:relative; display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:12px; }
.sf-doc .sf-related__card { position:relative; display:grid; grid-template-rows:auto auto auto 1fr auto; min-width:0; min-height:190px; padding:18px; background:var(--white); border:1px solid var(--line); border-radius:var(--r-xl); color:var(--deep-ink); text-decoration:none !important; box-shadow:var(--shadow-sm); overflow:hidden; transition:transform .2s ease, border-color .2s ease, box-shadow .2s ease; }
.sf-doc .sf-related__card::before { content:''; position:absolute; inset:0 0 auto; height:3px; background:linear-gradient(90deg, var(--primary), var(--secondary)); transform:scaleX(0); transform-origin:left; transition:transform .2s ease; }
.sf-doc .sf-related__card:hover { color:var(--deep-ink); border-color:rgba(3,72,96,.38); box-shadow:0 12px 28px rgba(3,72,96,.12); transform:translateY(-3px); }
.sf-doc .sf-related__card:hover::before { transform:scaleX(1); }
.sf-doc .sf-related__icon { display:flex; align-items:center; justify-content:center; width:38px; height:38px; margin-bottom:16px; border-radius:var(--r-lg); background:var(--neutral); color:var(--primary); }
.sf-doc .sf-related__icon svg { width:19px; height:19px; fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; }
.sf-doc .sf-related__kicker { margin-bottom:5px; font-family:var(--font-mono); font-size:.625rem; font-weight:500; line-height:1.4; letter-spacing:.1em; text-transform:uppercase; color:var(--slate); }
.sf-doc .sf-related__card-title { display:block; margin-bottom:7px; color:var(--deep-ink); font-family:var(--font-sans); font-size:1rem; font-weight:700; line-height:1.25; }
.sf-doc .sf-related__desc { color:var(--slate); font-size:.8125rem; line-height:1.5; }
.sf-doc .sf-related__action { display:flex; align-items:center; gap:6px; margin-top:16px; color:var(--primary); font-family:var(--font-sans); font-size:.75rem; font-weight:700; }
.sf-doc .sf-related__action svg { width:14px; height:14px; fill:none; stroke:currentColor; stroke-width:2; transition:transform .2s ease; }
.sf-doc .sf-related__card:hover .sf-related__action svg { transform:translateX(3px); }
.sf-doc .sf-related__grid--four { grid-template-columns:repeat(2, minmax(0, 1fr)); }
[data-color-mode="dark"] .sf-doc .sf-related { background:linear-gradient(135deg, rgba(0,224,184,.08) 0%, rgba(0,166,200,.045) 100%); border-color:var(--line); }
[data-color-mode="dark"] .sf-doc .sf-related__eyebrow, [data-color-mode="dark"] .sf-doc .sf-related__action { color:var(--secondary); }
[data-color-mode="dark"] .sf-doc .sf-related__card { background:rgba(255,255,255,.045); border-color:var(--line); box-shadow:none; }
[data-color-mode="dark"] .sf-doc .sf-related__card:hover { border-color:rgba(0,224,184,.5); box-shadow:0 12px 28px rgba(0,0,0,.28); }
[data-color-mode="dark"] .sf-doc .sf-related__icon { background:rgba(0,224,184,.1); color:var(--secondary); }
@media (prefers-color-scheme: dark) {
  html:not([data-color-mode="light"]) .sf-doc .sf-related { background:linear-gradient(135deg, rgba(0,224,184,.08) 0%, rgba(0,166,200,.045) 100%); border-color:var(--line); }
  html:not([data-color-mode="light"]) .sf-doc .sf-related__eyebrow, html:not([data-color-mode="light"]) .sf-doc .sf-related__action { color:var(--secondary); }
  html:not([data-color-mode="light"]) .sf-doc .sf-related__card { background:rgba(255,255,255,.045); border-color:var(--line); box-shadow:none; }
  html:not([data-color-mode="light"]) .sf-doc .sf-related__card:hover { border-color:rgba(0,224,184,.5); box-shadow:0 12px 28px rgba(0,0,0,.28); }
  html:not([data-color-mode="light"]) .sf-doc .sf-related__icon { background:rgba(0,224,184,.1); color:var(--secondary); }
}
@media (max-width: 820px) { .sf-doc .sf-related__grid { grid-template-columns:1fr 1fr; } }
@media (max-width: 640px) {
  .sf-doc .sf-related { margin-top:40px; padding:22px 18px; }
  .sf-doc .sf-related__head { grid-template-columns:1fr; gap:10px; }
  .sf-doc .sf-related__grid { grid-template-columns:1fr; }
  .sf-doc .sf-related__card { min-height:0; }
}
/* ══ END CANONICAL TUTORIAL STYLESHEET ══ */
</style>

<div class="sf-doc">

  
  <header class="sf-hero">
    <div class="sf-hero__copy">
      <p class="sf-hero__title">Deploy ThingsBoard on ALPON</p>
      <p class="sf-hero__lead">
        Connect your <strong>ALPON X5 AI</strong> or <strong>ALPON X4</strong> to <strong>ThingsBoard</strong> and
        stream telemetry into its dashboards. This guide sets up an MQTT integration in ThingsBoard, builds a small
        MQTT client container that publishes a test reading through an external broker, and deploys it through
        <strong>ALPON Cloud</strong>.
      </p>
      <div class="sf-hero__chips">
        <span class="sf-pill sf-pill--alpon-x5">ALPON X5 AI</span>
        <span class="sf-pill sf-pill--alpon-x4">ALPON X4</span>
        <span class="sf-pill">ThingsBoard</span>
        <span class="sf-pill">IoT platform</span>
      </div>
    </div>
  </header>


  
  <div class="sf-meta">
    <span class="sf-meta__badge">ALPON</span>
    <span class="sf-meta__sep">·</span>
    <span class="sf-meta__badge sf-meta__badge--mint">Tutorial</span>
    <span class="sf-meta__sep">·</span>
    <span>Containers</span>
    <span class="sf-meta__sep">·</span>
    <span>IoT platforms</span>
  </div>


  
  <div class="sf-aeo">
    <span class="sf-aeo__label">How do I deploy ThingsBoard on ALPON?</span>
    <p class="sf-aeo__text">
      Create an <strong>MQTT integration</strong> in ThingsBoard that listens on <code>v1/devices/+/telemetry</code>
      at <code>broker.hivemq.com:1883</code> with a TBEL uplink converter, build the <code>thingsboard-mqtt-alpon-x4</code>
      MQTT client image and push it to your <strong>Sixfab Container Registry</strong>, then use the
      <strong>Applications → Deploy</strong> panel on <strong>ALPON Cloud</strong> to launch it on your
      <strong>ALPON X5 AI</strong> or <strong>ALPON X4</strong> with the <code>TOPIC</code>, <code>CLIENT_ID</code>,
      <code>MQTT_SERVER</code>, and <code>MQTT_PORT</code> environment variables. The reading appears under the
      device's <strong>Latest telemetry</strong> tab in ThingsBoard.
    </p>
  </div>


  
  <nav class="sf-toc" aria-label="On this page">
    <span class="sf-toc__label">In this guide</span>
    <a class="sf-toc__item" href="#overview"><span class="sf-toc__num">01</span>Overview</a>
    <a class="sf-toc__item" href="#step-device"><span class="sf-toc__num">02</span>Create a device</a>
    <a class="sf-toc__item" href="#step-integration"><span class="sf-toc__num">03</span>Add the integration</a>
    <a class="sf-toc__item" href="#step-image"><span class="sf-toc__num">04</span>Add the container</a>
    <a class="sf-toc__item" href="#step-deploy"><span class="sf-toc__num">05</span>Deploy on ALPON</a>
    <a class="sf-toc__item" href="#step-verify"><span class="sf-toc__num">06</span>Check the data</a>
  </nav>


  
  <h2 id="overview">Overview</h2>

  <p><strong>ThingsBoard</strong> is an open-source IoT platform designed for the rapid development, management,
  and scaling of IoT projects. In this guide the <strong>ALPON X5 AI</strong> or <strong>ALPON X4</strong> runs a
  lightweight MQTT client container that publishes telemetry to an external MQTT broker; a ThingsBoard
  <strong>MQTT integration</strong> subscribes to that broker, decodes the payload with a TBEL converter, and maps
  it to the right device.</p>

  <p>The steps below are identical on ALPON X4 and ALPON X5 AI. For other integration types, converters, and
  dashboards, see the <a href="https://thingsboard.io/docs/" target="_blank" rel="noopener">official ThingsBoard
  documentation</a>.</p>

  <div class="sf-callout sf-callout--info">
    <div class="sf-callout__header">
      <svg class="sf-icon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>
      <span>Before you start</span>
    </div>
    <div class="sf-callout__content">
      <p>You need an <a href="https://connect.sixfab.com" target="_blank" rel="noopener">ALPON Cloud account</a>, a
      <a href="https://thingsboard.cloud" target="_blank" rel="noopener">ThingsBoard account</a>, and an ALPON X5 AI or
      ALPON X4 registered and activated on ALPON Cloud with an active internet connection — see the
      <a href="https://docs.sixfab.com/docs/alpon-x4-edge-computer-quickstart" target="_blank" rel="noopener">ALPON X4
      Getting Started page</a> for setup instructions. Docker must be installed on your build machine to build and push
      the image. Familiarity with IoT concepts, containerized applications, and ThingsBoard dashboards helps. New to
      container deployment? Start with
      <a href="https://docs.sixfab.com/docs/alpon-app-containerization-dockerfile-templates" target="_blank" rel="noopener">Containerize Apps for ALPON</a>.</p>
    </div>
  </div>


  
  <ol class="sf-step-list">

    
    <li class="sf-step" id="step-device">
      <div class="sf-step__header">
        <div class="sf-step__num">1</div>
        <h3 class="sf-step__title">Create a device on ThingsBoard (optional)</h3>
      </div>
      <div class="sf-step__body">
        <p>The integration can create the device automatically the first time data arrives, so you can skip this step
        if you prefer. To create it manually, log in to your ThingsBoard instance and navigate to
        <strong>Entities → Devices</strong> in the sidebar.</p>

        <span class="sf-fig-anchor" id="fig-tb-devices"></span>
        <figure class="sf-figure">
          <a href="#lb-tb-devices" aria-label="Open enlarged image">
            <img src="https://files.readme.io/ee3449c5a805c564a2bf1b29e564d336b634a770ef292b669887da55923d49ca-1.png" alt="ThingsBoard sidebar with Entities → Devices selected and the empty Devices table" loading="lazy">
          </a>
          <figcaption>The Devices page under Entities in ThingsBoard.</figcaption>
        </figure>

        <p>Click the <strong>+</strong> icon in the top-right corner of the table and select
        <strong>Add new device</strong>.</p>

        <span class="sf-fig-anchor" id="fig-tb-add-device"></span>
        <figure class="sf-figure">
          <a href="#lb-tb-add-device" aria-label="Open enlarged image">
            <img src="https://files.readme.io/7da9e307a577c5647cfb7fb7f2ad2555484172f0cb6e46d6fee9558698d65210-2.png" alt="The + menu on the ThingsBoard Devices table with Add new device highlighted" loading="lazy">
          </a>
          <figcaption>Adding a new device from the Devices table.</figcaption>
        </figure>

        <p>Enter the device name (for example <code>ALPON_X4</code>). No other changes are required at this time.
        Click <strong>Add</strong> and close the window — the device is created.</p>

        <span class="sf-fig-anchor" id="fig-tb-device-name"></span>
        <figure class="sf-figure">
          <a href="#lb-tb-device-name" aria-label="Open enlarged image">
            <img src="https://files.readme.io/b0fd43ac653214453fb995a6ce55bef5fbeef564fb3c6aa7588ada76aeadf1bd-3.png" alt="ThingsBoard Add new device dialog with the device name filled in" loading="lazy">
          </a>
          <figcaption>The Add new device dialog with only the name filled in.</figcaption>
        </figure>
      </div>
    </li>


    
    <li class="sf-step" id="step-integration">
      <div class="sf-step__header">
        <div class="sf-step__num">2</div>
        <h3 class="sf-step__title">Add the MQTT integration and topic filter</h3>
      </div>
      <div class="sf-step__body">
        <p>To transfer data from the ALPON to ThingsBoard via an external MQTT broker, you need an
        <strong>MQTT integration</strong> in ThingsBoard. The integration uses a <strong>topic filter</strong> to
        choose which MQTT topics to listen to and a <strong>data converter</strong> written in TBEL to process incoming
        data and map it to the appropriate device.</p>

        <p>In ThingsBoard, open the <strong>Integrations</strong> section in the left-side menu and click the
        <strong>+</strong> icon to add a new integration.</p>

        <span class="sf-fig-anchor" id="fig-int-add"></span>
        <figure class="sf-figure">
          <a href="#lb-int-add" aria-label="Open enlarged image">
            <img src="https://files.readme.io/051779d3a135cce4f01074790ee946cecb094b73b88dbf807b71520f0fae959e-5.png" alt="ThingsBoard Integrations page with the + button to add a new integration" loading="lazy">
          </a>
          <figcaption>The Integrations page in ThingsBoard.</figcaption>
        </figure>

        <p>Select <strong>MQTT</strong> as the integration type.</p>

        <span class="sf-fig-anchor" id="fig-int-mqtt"></span>
        <figure class="sf-figure">
          <a href="#lb-int-mqtt" aria-label="Open enlarged image">
            <img src="https://files.readme.io/7105665b818739f5fa4242191692ee91d048c532b972b9109f25a6e438b23eb6-6.png" alt="ThingsBoard Add integration dialog with MQTT selected as the integration type" loading="lazy">
          </a>
          <figcaption>Choosing MQTT as the integration type.</figcaption>
        </figure>

        <p>In the <strong>Uplink data converter</strong> step, select <strong>TBEL</strong>, replace the default decoder
        with the code below, and click <strong>Next</strong>.</p>

        <span class="sf-fig-anchor" id="fig-int-tbel"></span>
        <figure class="sf-figure">
          <a href="#lb-int-tbel" aria-label="Open enlarged image">
            <img src="https://files.readme.io/cf401c327d90ba423d9a75d421e94f9fea3e643b9e48ec8a8e5bd1f7cad02e78-7.png" alt="ThingsBoard uplink data converter step with TBEL selected and the decoder editor open" loading="lazy">
          </a>
          <figcaption>The uplink data converter step with TBEL selected.</figcaption>
        </figure>

        <div class="sf-terminal">
          <div class="sf-terminal__header">
            <span class="sf-terminal__dot sf-terminal__dot--r"></span>
            <span class="sf-terminal__dot sf-terminal__dot--y"></span>
            <span class="sf-terminal__dot sf-terminal__dot--g"></span>
            <span class="sf-terminal__title">TBEL · uplink decoder</span>
          </div>
          <div class="sf-terminal__body">
<pre>// Decode an uplink message from a buffer
// payload - array of bytes
// metadata - key/value object

/** Decoder **/

var payloadObj = decodeToJson(payload);

var deviceName = 'ALPON X4';
var deviceType = 'alpon';
var groupName = 'alpon devices';
var manufacturer = 'Sixfab';

var result = {
   deviceName: deviceName,
   deviceType: deviceType,

   groupName: groupName,
   attributes: {
       model: 'X4',
       serialNumber: '111111111',
       manufacturer: manufacturer
   },
   telemetry: {
       temperature: payloadObj.temperature,
   }
};

/** Helper functions 'decodeToString' and 'decodeToJson' are already built-in **/

return result;</pre>
          </div>
        </div>

        <p>Configure the broker details, then click <strong>Add</strong>:</p>

        <div class="sf-spec-card">
          <div class="sf-spec-card__body">
            <div class="sf-spec-row">
              <span class="sf-spec-row__key"><code>Host</code></span>
              <span class="sf-spec-row__val"><code>broker.hivemq.com</code></span>
            </div>
            <div class="sf-spec-row">
              <span class="sf-spec-row__key"><code>Port</code></span>
              <span class="sf-spec-row__val"><code>1883</code></span>
            </div>
            <div class="sf-spec-row">
              <span class="sf-spec-row__key"><code>Topic</code></span>
              <span class="sf-spec-row__val"><code>v1/devices/+/telemetry</code> — this filter determines which topics the integration listens to.</span>
            </div>
          </div>
        </div>

        <span class="sf-fig-anchor" id="fig-int-broker"></span>
        <figure class="sf-figure">
          <a href="#lb-int-broker" aria-label="Open enlarged image">
            <img src="https://files.readme.io/47f0614f4d9078f797d39af5cc903e1dc2c32ad83548df91c7d050d4cfb1b615-8.png" alt="ThingsBoard MQTT integration connection step with host broker.hivemq.com, port 1883, and topic filter v1/devices/+/telemetry" loading="lazy">
          </a>
          <figcaption>The MQTT connection settings with the HiveMQ broker and the topic filter.</figcaption>
        </figure>

        <h4>Understanding the topic filter</h4>
        <p>The topic filter <code>v1/devices/+/telemetry</code> uses a single-level wildcard (<code>+</code>) that
        matches any single topic level in that position. It will match topics such as:</p>
        <ul>
          <li><code>v1/devices/device1/telemetry</code></li>
          <li><code>v1/devices/sensorA/telemetry</code></li>
          <li><code>v1/devices/room23/telemetry</code></li>
        </ul>
        <p>It will not match topics such as:</p>
        <ul>
          <li><code>v1/devices/device1/sensor/telemetry</code> (because <code>+</code> matches only one level)</li>
          <li><code>v1/devices/telemetry</code> (because a level is missing)</li>
          <li><code>v1/attributes/+/client</code> (different topic structure)</li>
        </ul>
        <p>This structure lets the integration process data from multiple devices, each using a unique identifier
        (for example <code>device1</code>, <code>sensorA</code>, <code>room23</code>) in the topic. The ALPON can
        therefore send telemetry to ThingsBoard via the external broker, with the integration mapping the data to the
        correct device based on the topic structure.</p>
      </div>
    </li>


    
    <li class="sf-step" id="step-image">
      <div class="sf-step__header">
        <div class="sf-step__num">3</div>
        <h3 class="sf-step__title">Add the MQTT client container</h3>
      </div>
      <div class="sf-step__body">
        <p>Next, build the MQTT client image on your local computer and push it to your <strong>Sixfab Container
        Registry</strong> so it is available to the device. Make sure Docker is installed on your machine — download it
        from <a href="https://docs.docker.com/engine/install/" target="_blank" rel="noopener">docker.com</a> if
        needed.</p>

        <p>Create a file named <code>Dockerfile</code> with the following content to set up the environment for the
        MQTT client:</p>

        <div class="sf-terminal">
          <div class="sf-terminal__header">
            <span class="sf-terminal__dot sf-terminal__dot--r"></span>
            <span class="sf-terminal__dot sf-terminal__dot--y"></span>
            <span class="sf-terminal__dot sf-terminal__dot--g"></span>
            <span class="sf-terminal__title">Dockerfile</span>
          </div>
          <div class="sf-terminal__body">
<pre>FROM alpine:latest

RUN apk update &amp;&amp; apk add \\
    mosquitto-clients \\
    mosquitto \\
    python3 \\
    py3-pip \\
    bash

RUN pip3 install paho-mqtt --break-system-packages

WORKDIR /app

COPY mqtt_test.py /app/

CMD ["python3", "/app/mqtt_test.py"]</pre>
          </div>
        </div>

        <p>Create a file named <code>mqtt_test.py</code> in the same directory as the Dockerfile. This script makes the
        ALPON publish telemetry to ThingsBoard via MQTT — it connects to the broker, subscribes to the topic, and
        publishes a test <code>temperature</code> reading:</p>

        <div class="sf-terminal">
          <div class="sf-terminal__header">
            <span class="sf-terminal__dot sf-terminal__dot--r"></span>
            <span class="sf-terminal__dot sf-terminal__dot--y"></span>
            <span class="sf-terminal__dot sf-terminal__dot--g"></span>
            <span class="sf-terminal__title">python · mqtt_test.py</span>
          </div>
          <div class="sf-terminal__body">
<pre>import paho.mqtt.client as mqtt
import json
import ssl
import time
import os

MQTT_SERVER = os.getenv("MQTT_SERVER")
MQTT_PORT = os.getenv("MQTT_PORT")
CLIENT_ID = os.getenv("CLIENT_ID")
TOPIC = os.getenv("TOPIC")


def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    client.subscribe(TOPIC, qos=0)
    print(f"Subscribed to topic: {TOPIC}")

    # Publish a test message after connecting
    test_message = {
        "temperature": 26
    }
    client.publish(TOPIC, json.dumps(test_message), qos=0)
    print("Test message published.")

def on_message(client, userdata, msg):
    print(f"RECEIVED MESSAGE on {msg.topic}:")
    try:
        message = json.loads(msg.payload.decode())
        print(json.dumps(message, indent=4))
    except Exception as e:
        print(f"Error decoding JSON: {e}")
        print(msg.payload.decode())
# Set up MQTT client
client = mqtt.Client(client_id=CLIENT_ID, clean_session=True)

# Set up callbacks
client.on_connect = on_connect
client.on_message = on_message

# Enable SSL/TLS
client.connect(MQTT_SERVER, int(MQTT_PORT), 60)

# Start the loop
client.loop_forever()</pre>
          </div>
        </div>

        <p>Open a terminal in the directory containing the <code>Dockerfile</code> and <code>mqtt_test.py</code>, and
        build the <code>arm64</code> image:</p>

        <div class="sf-terminal">
          <div class="sf-terminal__header">
            <span class="sf-terminal__dot sf-terminal__dot--r"></span>
            <span class="sf-terminal__dot sf-terminal__dot--y"></span>
            <span class="sf-terminal__dot sf-terminal__dot--g"></span>
            <span class="sf-terminal__title">bash · build the image</span>
          </div>
          <div class="sf-terminal__body">
<pre>docker build --platform=linux/arm64 -t thingsboard-mqtt-alpon-x4:latest .</pre>
          </div>
        </div>

        <p>Then log in to <a href="https://connect.sixfab.com/#/registry" target="_blank" rel="noopener">Sixfab
        Registry</a>, click <strong>+ Add Container</strong>, and follow the prompts to push the image.</p>

        <span class="sf-fig-anchor" id="fig-registry"></span>
        <figure class="sf-figure">
          <a href="#lb-registry" aria-label="Open enlarged image">
            <img src="https://files.readme.io/f8a464bfaeec5c5158cc5f38f6bfb9db53a54f3fb03a08f4f3f791d3a3b708c4-9.png" alt="Sixfab Container Registry page on ALPON Cloud with the + Add Container button" loading="lazy">
          </a>
          <figcaption>The Sixfab Container Registry page on ALPON Cloud.</figcaption>
        </figure>

        <div class="sf-callout sf-callout--info">
          <div class="sf-callout__header">
            <svg class="sf-icon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"/></svg>
            <span>Pushing images to the Sixfab Container Registry</span>
          </div>
          <div class="sf-callout__content">
            <p>For the full walkthrough of tagging and pushing an image, see
            <a href="https://docs.sixfab.com/docs/alpon-update-containers-from-sixfab-registry" target="_blank" rel="noopener">Update Containers from the Sixfab Container Registry</a>
            and the <a href="https://docs.sixfab.com/docs/alpon-deploy-applications" target="_blank" rel="noopener">Deploy Applications</a> page.</p>
          </div>
        </div>
      </div>
    </li>


    
    <li class="sf-step" id="step-deploy">
      <div class="sf-step__header">
        <div class="sf-step__num">4</div>
        <h3 class="sf-step__title">Deploy the container on ALPON</h3>
      </div>
      <div class="sf-step__body">
        <p>Open your device in <a href="https://connect.sixfab.com" target="_blank" rel="noopener">ALPON
        Cloud</a>, go to the <strong>Applications</strong> section, and click <strong>+ Deploy</strong>. In the
        <strong>Deploy Container</strong> window, use these settings:</p>

        <div class="sf-spec-card">
          <div class="sf-spec-card__body">
            <div class="sf-spec-row">
              <span class="sf-spec-row__key"><code>Container Name</code></span>
              <span class="sf-spec-row__val"><code>thingsboard-mqtt-client</code></span>
            </div>
            <div class="sf-spec-row">
              <span class="sf-spec-row__key"><code>Image</code></span>
              <span class="sf-spec-row__val">The <code>thingsboard-mqtt-alpon-x4</code> image and tag you pushed to the Sixfab Container Registry.</span>
            </div>
            <div class="sf-spec-row">
              <span class="sf-spec-row__key"><code>Environment</code></span>
              <span class="sf-spec-row__val">Click <strong>+ Add More</strong> in the environment section and add the four variables in the table below.</span>
            </div>
          </div>
        </div>

        <div class="sf-table-wrap">
          <table class="sf-table">
            <thead>
              <tr><th scope="col">Key</th><th scope="col">Value</th></tr>
            </thead>
            <tbody>
              <tr><td><code>TOPIC</code></td><td><code>v1/devices/alponx4/telemetry</code></td></tr>
              <tr><td><code>CLIENT_ID</code></td><td><code>alponx4</code></td></tr>
              <tr><td><code>MQTT_SERVER</code></td><td><code>broker.hivemq.com</code></td></tr>
              <tr><td><code>MQTT_PORT</code></td><td><code>1883</code></td></tr>
            </tbody>
          </table>
        </div>

        <span class="sf-fig-anchor" id="fig-deploy"></span>
        <figure class="sf-figure">
          <a href="#lb-deploy" aria-label="Open enlarged image">
            <img src="https://files.readme.io/966d341e44d3d848126933820afb8a4a087bec945903edb8a72f2ac1b4556e4f-10.png" alt="ALPON Cloud Deploy Container window with the thingsboard-mqtt-alpon-x4 image and the TOPIC, CLIENT_ID, MQTT_SERVER, and MQTT_PORT environment variables" loading="lazy">
          </a>
          <figcaption>The Deploy Container window with the image selected and the four environment variables set.</figcaption>
        </figure>

        <p>Click <strong>+ Deploy</strong> to launch the MQTT client on the device.</p>

        <span class="sf-fig-anchor" id="fig-deploy-button"></span>
        <figure class="sf-figure">
          <a href="#lb-deploy-button" aria-label="Open enlarged image">
            <img src="https://files.readme.io/4d8d411f045980cf55c4b70f028f4f88cb17a37f401ade9c8f7a1b6896cca4e2-11.png" alt="The + Deploy button at the bottom of the ALPON Cloud Deploy Container window" loading="lazy">
          </a>
          <figcaption>Deploying the container from ALPON Cloud.</figcaption>
        </figure>
      </div>
    </li>


    
    <li class="sf-step" id="step-verify">
      <div class="sf-step__header">
        <div class="sf-step__num">5</div>
        <h3 class="sf-step__title">Check the data on ThingsBoard</h3>
      </div>
      <div class="sf-step__body">
        <p>Once the container is running, verify that telemetry is received and displayed in ThingsBoard. Log in to
        your ThingsBoard instance, navigate to <strong>Entities → Devices</strong>, and select your
        <strong>ALPON X4</strong> device. Open the <strong>Latest telemetry</strong> tab to view the
        <code>temperature</code> value sent by the container.</p>

        <span class="sf-fig-anchor" id="fig-telemetry"></span>
        <figure class="sf-figure">
          <a href="#lb-telemetry" aria-label="Open enlarged image">
            <img src="https://files.readme.io/f50c01b2342c91ad0098478d7fb1d9eb6f31657191923fa19df53573f3831de6-12.png" alt="ThingsBoard device details for ALPON X4 showing the temperature key with value 26 in the Latest telemetry tab" loading="lazy">
          </a>
          <figcaption>The test reading received by ThingsBoard under Latest telemetry.</figcaption>
        </figure>

        <p>If nothing appears, confirm the container is running in the Applications section and that the
        <code>TOPIC</code> value matches the integration's topic filter from step 2.</p>
      </div>
    </li>

  </ol>


  
  <div class="sf-callout sf-callout--success">
    <div class="sf-callout__header">
      <svg class="sf-icon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
      <span>Ready when…</span>
    </div>
    <div class="sf-callout__content">
      <ul>
        <li>The <code>thingsboard-mqtt-client</code> container shows as running in the Applications section.</li>
        <li>The MQTT integration in ThingsBoard shows the connection as active.</li>
        <li>The <strong>ALPON X4</strong> device lists a <code>temperature</code> reading under <strong>Latest telemetry</strong>.</li>
      </ul>
      <p>The ALPON is now integrated with ThingsBoard over MQTT for real-time data collection: you created a device in
      ThingsBoard, added an MQTT integration, and deployed an MQTT client through ALPON Cloud. For further assistance,
      refer to the <a href="https://thingsboard.io/docs/" target="_blank" rel="noopener">ThingsBoard documentation</a>
      or contact <a href="https://sixfab.com/contact/" target="_blank" rel="noopener">Sixfab support</a>.</p>
    </div>
  </div>


  
  <div class="sf-lightbox" id="lb-tb-devices" role="dialog" aria-label="Enlarged image: ThingsBoard sidebar">
    <a class="sf-lightbox__backdrop" href="#fig-tb-devices" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-tb-devices" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-tb-devices" aria-label="Close">
        <img src="https://files.readme.io/ee3449c5a805c564a2bf1b29e564d336b634a770ef292b669887da55923d49ca-1.png" alt="ThingsBoard sidebar">
      </a>
      <div class="sf-lightbox__caption">The Devices page under Entities in ThingsBoard.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-tb-add-device" role="dialog" aria-label="Enlarged image: The + menu on the ThingsBoard Devices table">
    <a class="sf-lightbox__backdrop" href="#fig-tb-add-device" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-tb-add-device" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-tb-add-device" aria-label="Close">
        <img src="https://files.readme.io/7da9e307a577c5647cfb7fb7f2ad2555484172f0cb6e46d6fee9558698d65210-2.png" alt="The + menu on the ThingsBoard Devices table">
      </a>
      <div class="sf-lightbox__caption">Adding a new device from the Devices table.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-tb-device-name" role="dialog" aria-label="Enlarged image: ThingsBoard Add new device dialog">
    <a class="sf-lightbox__backdrop" href="#fig-tb-device-name" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-tb-device-name" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-tb-device-name" aria-label="Close">
        <img src="https://files.readme.io/b0fd43ac653214453fb995a6ce55bef5fbeef564fb3c6aa7588ada76aeadf1bd-3.png" alt="ThingsBoard Add new device dialog">
      </a>
      <div class="sf-lightbox__caption">The Add new device dialog with only the name filled in.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-int-add" role="dialog" aria-label="Enlarged image: ThingsBoard Integrations page">
    <a class="sf-lightbox__backdrop" href="#fig-int-add" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-int-add" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-int-add" aria-label="Close">
        <img src="https://files.readme.io/051779d3a135cce4f01074790ee946cecb094b73b88dbf807b71520f0fae959e-5.png" alt="ThingsBoard Integrations page">
      </a>
      <div class="sf-lightbox__caption">The Integrations page in ThingsBoard.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-int-mqtt" role="dialog" aria-label="Enlarged image: ThingsBoard Add integration dialog">
    <a class="sf-lightbox__backdrop" href="#fig-int-mqtt" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-int-mqtt" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-int-mqtt" aria-label="Close">
        <img src="https://files.readme.io/7105665b818739f5fa4242191692ee91d048c532b972b9109f25a6e438b23eb6-6.png" alt="ThingsBoard Add integration dialog">
      </a>
      <div class="sf-lightbox__caption">Choosing MQTT as the integration type.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-int-tbel" role="dialog" aria-label="Enlarged image: ThingsBoard uplink data converter step">
    <a class="sf-lightbox__backdrop" href="#fig-int-tbel" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-int-tbel" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-int-tbel" aria-label="Close">
        <img src="https://files.readme.io/cf401c327d90ba423d9a75d421e94f9fea3e643b9e48ec8a8e5bd1f7cad02e78-7.png" alt="ThingsBoard uplink data converter step">
      </a>
      <div class="sf-lightbox__caption">The uplink data converter step with TBEL selected.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-int-broker" role="dialog" aria-label="Enlarged image: ThingsBoard MQTT integration connection step">
    <a class="sf-lightbox__backdrop" href="#fig-int-broker" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-int-broker" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-int-broker" aria-label="Close">
        <img src="https://files.readme.io/47f0614f4d9078f797d39af5cc903e1dc2c32ad83548df91c7d050d4cfb1b615-8.png" alt="ThingsBoard MQTT integration connection step">
      </a>
      <div class="sf-lightbox__caption">The MQTT connection settings with the HiveMQ broker and the topic filter.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-registry" role="dialog" aria-label="Enlarged image: Sixfab Container Registry page on ALPON Cloud">
    <a class="sf-lightbox__backdrop" href="#fig-registry" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-registry" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-registry" aria-label="Close">
        <img src="https://files.readme.io/f8a464bfaeec5c5158cc5f38f6bfb9db53a54f3fb03a08f4f3f791d3a3b708c4-9.png" alt="Sixfab Container Registry page on ALPON Cloud">
      </a>
      <div class="sf-lightbox__caption">The Sixfab Container Registry page on ALPON Cloud.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-deploy" role="dialog" aria-label="Enlarged image: ALPON Cloud Deploy Container window">
    <a class="sf-lightbox__backdrop" href="#fig-deploy" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-deploy" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-deploy" aria-label="Close">
        <img src="https://files.readme.io/966d341e44d3d848126933820afb8a4a087bec945903edb8a72f2ac1b4556e4f-10.png" alt="ALPON Cloud Deploy Container window">
      </a>
      <div class="sf-lightbox__caption">The Deploy Container window with the image selected and the four environment variables set.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-deploy-button" role="dialog" aria-label="Enlarged image: The + Deploy button at the bottom of the ALPON Cloud Deploy Container window">
    <a class="sf-lightbox__backdrop" href="#fig-deploy-button" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-deploy-button" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-deploy-button" aria-label="Close">
        <img src="https://files.readme.io/4d8d411f045980cf55c4b70f028f4f88cb17a37f401ade9c8f7a1b6896cca4e2-11.png" alt="The + Deploy button at the bottom of the ALPON Cloud Deploy Container window">
      </a>
      <div class="sf-lightbox__caption">Deploying the container from ALPON Cloud.</div>
    </div>
  </div>

  <div class="sf-lightbox" id="lb-telemetry" role="dialog" aria-label="Enlarged image: ThingsBoard device details for ALPON X4">
    <a class="sf-lightbox__backdrop" href="#fig-telemetry" aria-label="Close"></a>
    <a class="sf-lightbox__close" href="#fig-telemetry" aria-label="Close enlarged image">
      <svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </a>
    <div class="sf-lightbox__inner">
      <a class="sf-lightbox__img-wrap" href="#fig-telemetry" aria-label="Close">
        <img src="https://files.readme.io/f50c01b2342c91ad0098478d7fb1d9eb6f31657191923fa19df53573f3831de6-12.png" alt="ThingsBoard device details for ALPON X4">
      </a>
      <div class="sf-lightbox__caption">The test reading received by ThingsBoard under Latest telemetry.</div>
    </div>
  </div>

</div>
`}</HTMLBlock>

> **Production image policy:** Replace floating `:latest` references with a reviewed immutable tag or digest, then record the selected version for rollback.

<HTMLBlock>{`
<div class="sf-doc">
  <section class="sf-related" aria-labelledby="related-guides-heading">
    <div class="sf-related__head">
      <div>
        <span class="sf-related__eyebrow">Continue exploring</span>
        <h2 class="sf-related__title" id="related-guides-heading">Related guides</h2>
      </div>
      <p class="sf-related__intro">Build on this workflow with deployment, fleet-management, and hardware guidance for the ALPON platform.</p>
    </div>
    <div class="sf-related__grid sf-related__grid--four">
      <a class="sf-related__card" href="/docs/alpon-deploy-applications">
        <span class="sf-related__icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 3v12"/><path d="m7 10 5 5 5-5"/><path d="M5 21h14"/></svg></span>
        <span class="sf-related__kicker">Workflow</span>
        <strong class="sf-related__card-title">Deploy Applications on ALPON</strong>
        <span class="sf-related__desc">Push an ARM64 image, configure its runtime, and launch it from ALPON Cloud.</span>
        <span class="sf-related__action">Open guide <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg></span>
      </a>
      <a class="sf-related__card" href="/docs/alpon-cloud">
        <span class="sf-related__icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18"/><path d="M8 14h3"/></svg></span>
        <span class="sf-related__kicker">Platform</span>
        <strong class="sf-related__card-title">ALPON Cloud</strong>
        <span class="sf-related__desc">Manage devices, applications, connectivity, and remote operations from one workspace.</span>
        <span class="sf-related__action">Open guide <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg></span>
      </a>
      <a class="sf-related__card" href="/docs/alpon-device-comparison">
        <span class="sf-related__icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="5" y="3" width="14" height="18" rx="2"/><path d="M9 7h6M9 11h6M9 15h3"/></svg></span>
        <span class="sf-related__kicker">Hardware</span>
        <strong class="sf-related__card-title">Compare ALPON devices</strong>
        <span class="sf-related__desc">Compare ALPON X4 and ALPON X5 AI capabilities for your edge workload.</span>
        <span class="sf-related__action">Open guide <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg></span>
      </a>
      <a class="sf-related__card" href="/docs/alpon-x4-edge-computer-quickstart">
        <span class="sf-related__icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 3a9 9 0 1 0 9 9"/><path d="m12 7 4 5-4 5"/></svg></span>
        <span class="sf-related__kicker">Quickstart</span>
        <strong class="sf-related__card-title">ALPON X4 Getting Started</strong>
        <span class="sf-related__desc">Bring an ALPON X4 online and complete the first device setup.</span>
        <span class="sf-related__action">Open guide <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg></span>
      </a>
    </div>
  </section>
</div>
`}</HTMLBlock>