Has Anyone Integrated Wix Bookings with Harvia Xenio Sauna (via API)?

Hi all,

I’m working on a client project involving a Harvia WiFi sauna system and I’m looking for guidance from developers who may have worked with similar smart device integrations.


:bullseye: Goal of the Project

We need to connect Wix Bookings to a Harvia Xenio CX170XW sauna controller, so that:

:check_mark: Whenever a customer books a session through Wix Bookings
:check_mark: The sauna automatically starts heating 30 minutes before the session begins

This is a developer-level task, and we know that Harvia provides an API for this controller model.


:electric_plug: Device Info


:light_bulb: What We’re Exploring

  • Has anyone integrated Harvia’s API with custom web apps or smart systems?

  • Can the Wix Bookings backend (via Velo) be used to schedule API calls 30 minutes before booking start?


:backhand_index_pointing_right: If you’ve done something similar or have worked with Harvia’s API, I’d love to hear how you approached it.

:rocket: If you’re open to it, I’d be happy to connect you directly with the client so you can discuss the technical implementation further.

Thanks in advance! :raising_hands:

Betina

Interesting Project!

If you need assistance → send me a PRIVATE-MESSAGE.

29-days and anyone has replied? :thinking:

Well, your project is a bigger one!!!

  1. There is no official API available on the market, provided by HARVIA.
  2. Normaly there is only the official controling system available → controlled by phone.
  3. Reverse-Engeneering capabilities will be needed.
  4. Of course there are also some other possibilities available of how to solve your problem.

Need some example FRONTEND-HARVIA-CONTROLER-UX/UI ???

Here it is… → a smal simulation for you and your → CLIENT…

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Harvia Sauna Control System</title>
<style>
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
  
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  
  :root {
    --primary: #FF6B35;
    --primary-dark: #E85A28;
    --primary-light: #FF8F5F;
    --bg-dark: #0A0E1A;
    --bg-card: #12172B;
    --bg-elevated: #1A2038;
    --text-primary: #FFFFFF;
    --text-secondary: #A0AEC0;
    --text-muted: #718096;
    --border: rgba(255, 255, 255, 0.06);
    --success: #48BB78;
    --warning: #ECC94B;
    --danger: #F56565;
    --glass: rgba(255, 255, 255, 0.03);
    --glow: rgba(255, 107, 53, 0.3);
  }
  
  body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
    background: linear-gradient(135deg, #0A0E1A 0%, #1A1F35 100%);
    color: var(--text-primary);
    min-height: 100vh;
    padding: 20px;
    overflow-x: hidden;
  }
  
  .container {
    max-width: 1400px;
    margin: 0 auto;
  }
  
  /* Header */
  .header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 32px;
    padding: 24px;
    background: var(--bg-card);
    border-radius: 16px;
    border: 1px solid var(--border);
  }
  
  .brand {
    display: flex;
    align-items: center;
    gap: 16px;
  }
  
  .logo {
    width: 56px;
    height: 56px;
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 28px;
    box-shadow: 0 8px 24px var(--glow);
  }
  
  .brand-text h1 {
    font-size: 24px;
    font-weight: 700;
    margin-bottom: 4px;
  }
  
  .brand-text p {
    font-size: 13px;
    color: var(--text-muted);
  }
  
  .connection-status {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    background: var(--glass);
    border-radius: 8px;
    border: 1px solid var(--border);
  }
  
  .status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--success);
    animation: pulse 2s infinite;
  }
  
  @keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
  }
  
  /* Grid Layout */
  .grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    margin-bottom: 24px;
  }
  
  .card {
    background: var(--bg-card);
    border-radius: 16px;
    padding: 28px;
    border: 1px solid var(--border);
    position: relative;
    overflow: hidden;
  }
  
  .card::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--primary), transparent);
    opacity: 0.3;
  }
  
  .card-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-bottom: 20px;
  }
  
  /* Temperature Display */
  .temp-display {
    text-align: center;
    padding: 32px 0;
  }
  
  .temp-main {
    font-size: 96px;
    font-weight: 700;
    line-height: 1;
    background: linear-gradient(135deg, var(--primary-light), var(--primary));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    margin-bottom: 16px;
    position: relative;
  }
  
  .temp-unit {
    font-size: 48px;
    opacity: 0.7;
  }
  
  .temp-label {
    font-size: 14px;
    color: var(--text-muted);
    margin-bottom: 8px;
  }
  
  .temp-target {
    font-size: 16px;
    color: var(--text-secondary);
    margin-top: 12px;
  }
  
  .temp-bar {
    width: 100%;
    height: 6px;
    background: var(--bg-elevated);
    border-radius: 3px;
    margin-top: 24px;
    overflow: hidden;
  }
  
  .temp-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--primary), var(--primary-light));
    border-radius: 3px;
    transition: width 1s ease;
    box-shadow: 0 0 16px var(--glow);
  }
  
  /* Power Control */
  .power-control {
    text-align: center;
    padding: 20px 0;
  }
  
  .power-button {
    width: 200px;
    height: 200px;
    border-radius: 50%;
    border: none;
    background: linear-gradient(135deg, var(--bg-elevated), var(--bg-card));
    cursor: pointer;
    position: relative;
    transition: all 0.3s ease;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
  }
  
  .power-button:hover {
    transform: scale(1.05);
  }
  
  .power-button.active {
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    box-shadow: 0 8px 48px var(--glow);
  }
  
  .power-icon {
    font-size: 64px;
    transition: all 0.3s ease;
  }
  
  .power-text {
    font-size: 18px;
    font-weight: 600;
  }
  
  .power-status {
    margin-top: 24px;
    font-size: 14px;
    color: var(--text-muted);
  }
  
  /* Temperature Slider */
  .slider-container {
    margin-top: 32px;
  }
  
  .slider-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
  }
  
  .slider-value {
    font-size: 32px;
    font-weight: 700;
    color: var(--primary);
  }
  
  .slider {
    -webkit-appearance: none;
    width: 100%;
    height: 8px;
    border-radius: 4px;
    background: var(--bg-elevated);
    outline: none;
    position: relative;
  }
  
  .slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    cursor: pointer;
    box-shadow: 0 4px 16px var(--glow);
    transition: all 0.2s ease;
  }
  
  .slider::-webkit-slider-thumb:hover {
    transform: scale(1.2);
    box-shadow: 0 6px 24px var(--glow);
  }
  
  .slider::-moz-range-thumb {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    cursor: pointer;
    border: none;
    box-shadow: 0 4px 16px var(--glow);
  }
  
  .temp-range {
    display: flex;
    justify-content: space-between;
    margin-top: 8px;
    font-size: 12px;
    color: var(--text-muted);
  }
  
  /* Controls Grid */
  .controls-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
    margin-top: 24px;
  }
  
  .control-item {
    background: var(--glass);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    transition: all 0.3s ease;
  }
  
  .control-item:hover {
    background: var(--bg-elevated);
    border-color: var(--primary);
    cursor: pointer;
  }
  
  .control-info {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  
  .control-icon {
    width: 40px;
    height: 40px;
    border-radius: 10px;
    background: var(--bg-elevated);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
  }
  
  .control-label {
    font-size: 14px;
    font-weight: 500;
  }
  
  .toggle-switch {
    position: relative;
    width: 48px;
    height: 26px;
    background: var(--bg-elevated);
    border-radius: 13px;
    cursor: pointer;
    transition: all 0.3s ease;
  }
  
  .toggle-switch.active {
    background: var(--primary);
  }
  
  .toggle-switch::before {
    content: '';
    position: absolute;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: white;
    top: 3px;
    left: 3px;
    transition: all 0.3s ease;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  }
  
  .toggle-switch.active::before {
    transform: translateX(22px);
  }
  
  /* Stats Grid */
  .stats-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
  }
  
  .stat-card {
    background: var(--glass);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 20px;
    text-align: center;
  }
  
  .stat-value {
    font-size: 28px;
    font-weight: 700;
    margin-bottom: 8px;
    color: var(--primary);
  }
  
  .stat-label {
    font-size: 12px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 1px;
  }
  
  /* Timer */
  .timer-display {
    text-align: center;
    padding: 24px 0;
  }
  
  .timer-value {
    font-size: 56px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    margin-bottom: 16px;
  }
  
  .timer-controls {
    display: flex;
    gap: 12px;
    justify-content: center;
    margin-top: 20px;
  }
  
  .btn {
    padding: 12px 24px;
    border-radius: 8px;
    border: none;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s ease;
    font-size: 14px;
  }
  
  .btn-primary {
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    color: white;
    box-shadow: 0 4px 16px var(--glow);
  }
  
  .btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 24px var(--glow);
  }
  
  .btn-secondary {
    background: var(--bg-elevated);
    color: var(--text-secondary);
    border: 1px solid var(--border);
  }
  
  .btn-secondary:hover {
    background: var(--bg-card);
    border-color: var(--primary);
  }
  
  /* Presets */
  .presets {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
  }
  
  .preset-btn {
    flex: 1;
    min-width: 140px;
    padding: 16px;
    background: var(--glass);
    border: 1px solid var(--border);
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.3s ease;
    text-align: center;
  }
  
  .preset-btn:hover {
    background: var(--bg-elevated);
    border-color: var(--primary);
    transform: translateY(-2px);
  }
  
  .preset-btn.active {
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    border-color: var(--primary);
    box-shadow: 0 4px 16px var(--glow);
  }
  
  .preset-name {
    font-weight: 600;
    margin-bottom: 4px;
  }
  
  .preset-temp {
    font-size: 12px;
    color: var(--text-muted);
  }
  
  /* Humidity Display */
  .humidity-circle {
    width: 160px;
    height: 160px;
    margin: 20px auto;
    position: relative;
  }
  
  .humidity-circle svg {
    transform: rotate(-90deg);
  }
  
  .humidity-value {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 36px;
    font-weight: 700;
    color: var(--primary);
  }
  
  /* Notifications */
  .notification {
    position: fixed;
    top: 20px;
    right: 20px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 16px 20px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: center;
    gap: 12px;
    transform: translateX(400px);
    transition: transform 0.3s ease;
    z-index: 1000;
  }
  
  .notification.show {
    transform: translateX(0);
  }
  
  .notification-icon {
    font-size: 24px;
  }
  
  /* Responsive */
  @media (max-width: 1024px) {
    .grid {
      grid-template-columns: 1fr;
    }
    
    .stats-grid {
      grid-template-columns: repeat(2, 1fr);
    }
  }
  
  @media (max-width: 640px) {
    .controls-grid {
      grid-template-columns: 1fr;
    }
    
    .presets {
      flex-direction: column;
    }
    
    .preset-btn {
      min-width: 100%;
    }
  }
</style>
</head>
<body>
  <div class="container">
    <!-- Header -->
    <div class="header">
      <div class="brand">
        <div class="logo">H</div>
        <div class="brand-text">
          <h1>HARVIA</h1>
          <p>Professional Sauna Control System</p>
        </div>
      </div>
      <div class="connection-status">
        <div class="status-dot"></div>
        <span>Connected</span>
      </div>
    </div>
    
    <!-- Main Grid -->
    <div class="grid">
      <!-- Temperature Display -->
      <div class="card">
        <div class="card-title">Current Temperature</div>
        <div class="temp-display">
          <div class="temp-label">Cabin Temperature</div>
          <div class="temp-main">
            <span id="currentTemp">22</span><span class="temp-unit">°</span>
          </div>
          <div class="temp-target">Target: <span id="targetTemp">80</span>°C</div>
          <div class="temp-bar">
            <div class="temp-bar-fill" id="tempProgress"></div>
          </div>
        </div>
      </div>
      
      <!-- Power Control -->
      <div class="card">
        <div class="card-title">Power Control</div>
        <div class="power-control">
          <button class="power-button" id="powerBtn">
            <div class="power-icon">⚡</div>
            <div class="power-text">Start</div>
          </button>
          <div class="power-status" id="powerStatus">System ready</div>
        </div>
      </div>
    </div>
    
    <!-- Secondary Grid -->
    <div class="grid">
      <!-- Temperature Control -->
      <div class="card">
        <div class="card-title">Temperature Settings</div>
        <div class="slider-container">
          <div class="slider-header">
            <span>Set Target Temperature</span>
            <span class="slider-value"><span id="sliderValue">80</span>°C</span>
          </div>
          <input type="range" min="40" max="110" value="80" class="slider" id="tempSlider">
          <div class="temp-range">
            <span>40°C</span>
            <span>110°C</span>
          </div>
        </div>
        
        <div class="card-title" style="margin-top: 32px;">Quick Presets</div>
        <div class="presets">
          <div class="preset-btn" data-temp="70">
            <div class="preset-name">Mild</div>
            <div class="preset-temp">70°C</div>
          </div>
          <div class="preset-btn" data-temp="80">
            <div class="preset-name">Traditional</div>
            <div class="preset-temp">80°C</div>
          </div>
          <div class="preset-btn" data-temp="90">
            <div class="preset-name">Hot</div>
            <div class="preset-temp">90°C</div>
          </div>
          <div class="preset-btn" data-temp="100">
            <div class="preset-name">Extreme</div>
            <div class="preset-temp">100°C</div>
          </div>
        </div>
      </div>
      
      <!-- Additional Controls -->
      <div class="card">
        <div class="card-title">Additional Controls</div>
        <div class="controls-grid">
          <div class="control-item">
            <div class="control-info">
              <div class="control-icon">💡</div>
              <div class="control-label">Lights</div>
            </div>
            <div class="toggle-switch" id="lightToggle"></div>
          </div>
          
          <div class="control-item">
            <div class="control-info">
              <div class="control-icon">🌀</div>
              <div class="control-label">Ventilation</div>
            </div>
            <div class="toggle-switch" id="fanToggle"></div>
          </div>
          
          <div class="control-item">
            <div class="control-info">
              <div class="control-icon">💧</div>
              <div class="control-label">Steam</div>
            </div>
            <div class="toggle-switch" id="steamToggle"></div>
          </div>
          
          <div class="control-item">
            <div class="control-info">
              <div class="control-icon">🎵</div>
              <div class="control-label">Audio</div>
            </div>
            <div class="toggle-switch" id="audioToggle"></div>
          </div>
        </div>
        
        <div class="card-title" style="margin-top: 32px;">Session Timer</div>
        <div class="timer-display">
          <div class="timer-value" id="timerDisplay">00:00</div>
          <div class="timer-controls">
            <button class="btn btn-secondary" id="timerStart">Start Timer</button>
            <button class="btn btn-secondary" id="timerReset">Reset</button>
          </div>
        </div>
      </div>
    </div>
    
    <!-- Stats -->
    <div class="card">
      <div class="card-title">Session Statistics</div>
      <div class="stats-grid">
        <div class="stat-card">
          <div class="stat-value" id="statHeat">0%</div>
          <div class="stat-label">Heating Progress</div>
        </div>
        <div class="stat-card">
          <div class="stat-value" id="statHumidity">35%</div>
          <div class="stat-label">Humidity</div>
        </div>
        <div class="stat-card">
          <div class="stat-value" id="statEnergy">0.0</div>
          <div class="stat-label">Energy (kWh)</div>
        </div>
        <div class="stat-card">
          <div class="stat-value" id="statSessions">12</div>
          <div class="stat-label">Sessions Today</div>
        </div>
      </div>
    </div>
  </div>
  
  <!-- Notification -->
  <div class="notification" id="notification">
    <span class="notification-icon">✓</span>
    <span id="notificationText">Action completed</span>
  </div>

  <script>
    // Simulation State
    const state = {
      power: false,
      currentTemp: 22,
      targetTemp: 80,
      lights: false,
      fan: false,
      steam: false,
      audio: false,
      timerActive: false,
      timerSeconds: 0,
      energy: 0,
      humidity: 35,
      sessionsToday: 0
    };
    
    // DOM Elements
    const powerBtn = document.getElementById('powerBtn');
    const currentTempEl = document.getElementById('currentTemp');
    const targetTempEl = document.getElementById('targetTemp');
    const tempSlider = document.getElementById('tempSlider');
    const sliderValue = document.getElementById('sliderValue');
    const powerStatus = document.getElementById('powerStatus');
    const tempProgress = document.getElementById('tempProgress');
    const lightToggle = document.getElementById('lightToggle');
    const fanToggle = document.getElementById('fanToggle');
    const steamToggle = document.getElementById('steamToggle');
    const audioToggle = document.getElementById('audioToggle');
    const timerDisplay = document.getElementById('timerDisplay');
    const timerStart = document.getElementById('timerStart');
    const timerReset = document.getElementById('timerReset');
    const statHeat = document.getElementById('statHeat');
    const statHumidity = document.getElementById('statHumidity');
    const statEnergy = document.getElementById('statEnergy');
    const statSessions = document.getElementById('statSessions');
    
    // Set initial active preset (80°C)
    document.querySelector('.preset-btn[data-temp="80"]').classList.add('active');
    
    // Notification
    function showNotification(message) {
      const notif = document.getElementById('notification');
      const notifText = document.getElementById('notificationText');
      notifText.textContent = message;
      notif.classList.add('show');
      setTimeout(() => notif.classList.remove('show'), 3000);
    }
    
    // Power Control
    powerBtn.addEventListener('click', () => {
      state.power = !state.power;
      if (state.power) {
        powerBtn.classList.add('active');
        powerBtn.querySelector('.power-text').textContent = 'Stop';
        powerStatus.textContent = 'Heating active';
        state.sessionsToday++;
        statSessions.textContent = state.sessionsToday;
        showNotification('Sauna heating started');
      } else {
        powerBtn.classList.remove('active');
        powerBtn.querySelector('.power-text').textContent = 'Start';
        powerStatus.textContent = 'System ready';
        showNotification('Sauna stopped');
      }
    });
    
    // Temperature Slider
    tempSlider.addEventListener('input', (e) => {
      state.targetTemp = parseInt(e.target.value);
      sliderValue.textContent = state.targetTemp;
      targetTempEl.textContent = state.targetTemp;
    });
    
    tempSlider.addEventListener('change', () => {
      showNotification(`Target temperature set to ${state.targetTemp}°C`);
    });
    
    // Presets
    document.querySelectorAll('.preset-btn').forEach(btn => {
      btn.addEventListener('click', () => {
        // Remove active from all presets
        document.querySelectorAll('.preset-btn').forEach(b => b.classList.remove('active'));
        // Add active to clicked preset
        btn.classList.add('active');
        
        const temp = parseInt(btn.dataset.temp);
        state.targetTemp = temp;
        tempSlider.value = temp;
        sliderValue.textContent = temp;
        targetTempEl.textContent = temp;
        showNotification(`Preset applied: ${temp}°C`);
      });
    });
    
    // Toggle Controls
    function setupToggle(element, stateKey, label) {
      element.addEventListener('click', () => {
        state[stateKey] = !state[stateKey];
        element.classList.toggle('active');
        showNotification(`${label} ${state[stateKey] ? 'enabled' : 'disabled'}`);
      });
    }
    
    setupToggle(lightToggle, 'lights', 'Lights');
    setupToggle(fanToggle, 'fan', 'Ventilation');
    setupToggle(steamToggle, 'steam', 'Steam');
    setupToggle(audioToggle, 'audio', 'Audio');
    
    // Timer
    let timerInterval;
    
    timerStart.addEventListener('click', () => {
      state.timerActive = !state.timerActive;
      if (state.timerActive) {
        timerStart.textContent = 'Pause Timer';
        timerInterval = setInterval(() => {
          state.timerSeconds++;
          updateTimer();
        }, 1000);
      } else {
        timerStart.textContent = 'Start Timer';
        clearInterval(timerInterval);
      }
    });
    
    timerReset.addEventListener('click', () => {
      state.timerSeconds = 0;
      state.timerActive = false;
      timerStart.textContent = 'Start Timer';
      clearInterval(timerInterval);
      updateTimer();
    });
    
    function updateTimer() {
      const mins = Math.floor(state.timerSeconds / 60);
      const secs = state.timerSeconds % 60;
      timerDisplay.textContent = `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
    }
    
    // Simulation Loop
    setInterval(() => {
      if (state.power) {
        // Heat up simulation
        if (state.currentTemp < state.targetTemp) {
          state.currentTemp += 0.5;
          state.energy += 0.001;
        } else if (state.currentTemp > state.targetTemp) {
          state.currentTemp -= 0.3;
        }
        
        // Humidity changes with steam
        if (state.steam && state.humidity < 70) {
          state.humidity += 0.5;
        } else if (!state.steam && state.humidity > 25) {
          state.humidity -= 0.3;
        }
      } else {
        // Cool down simulation
        if (state.currentTemp > 22) {
          state.currentTemp -= 0.2;
        }
      }
      
      // Update UI
      currentTempEl.textContent = Math.round(state.currentTemp);
      const progress = Math.min(100, (state.currentTemp / state.targetTemp) * 100);
      tempProgress.style.width = progress + '%';
      statHeat.textContent = Math.round(progress) + '%';
      statHumidity.textContent = Math.round(state.humidity) + '%';
      statEnergy.textContent = state.energy.toFixed(2);
      statSessions.textContent = state.sessionsToday;
      
    }, 1000);
  </script>
</body>
</html>

1) COPY the shown code.
2) Search for --> CODE-PEN <-- or --> JS-Fiddle <--
3) Paste the code into the --> HTML-SECTION <-- 
4) Save and run the project.
5) Take a look of what is already available, what is missing and what could be improved.

**NEXT STEPS:**
1) Decide of how you want to connect your HARVIA-SAUNA-CONTROLLER with a WEB-API (or in your case --> Wix).
2) ...secret info....
3) ...secret info....
4) ...secret info....
5) ...secret info....

LET’S TAKE A SAUNA-SESSION …

VN-SAUNA