27 Oct 2026

Automation KeyPad Development

Automation KeyPad Development in PHP and HMTL

  • Raymond Chauke

    Senior Engineer

Automation KeyPad Development
<?php
/**
 * HSSP 3D SMART CONTROL PANEL WITH LIVE DEVICE STATUS
 * Drupal  PHP Filter snippet.
 * Command file: DRUPAL_ROOT/2r.txt
 * Live status URLs: https://yoursite.com/ufo/line1state.txt,
 *                    https://yoursite.com/ufo/line2state.txt,
 *                    https://yoursite.com/ufo/line3state.txt
 */

$hssp_commands = array(
    'line1on', 'line1off',
    'line2on', 'line2off',
    'line3on', 'line3off',
    'iddle'
);

$hssp_file = DRUPAL_ROOT . '/2r.txt';
$hssp_token = drupal_get_token('hssp_3d_control');

if (!file_exists($hssp_file)) {
    @file_put_contents($hssp_file, 'iddle', LOCK_EX);
}

/* AJAX endpoint for commands and status polling. */
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['hssp_ajax'])) {
    $token = isset($_POST['hssp_token']) ? (string) $_POST['hssp_token'] : '';

    if (!drupal_valid_token($token, 'hssp_3d_control')) {
        print drupal_json_encode(array(
            'ok' => FALSE,
            'message' => 'Invalid security token. Reload the page.'
        ));
        exit;
    }

    $action = isset($_POST['hssp_action']) ? (string) $_POST['hssp_action'] : 'command';

    /* Read all three status text files. This request does not write 2r.txt. */
    if ($action === 'status') {
        $status_files = array(
            '1' => DRUPAL_ROOT . '/line1state.txt',
            '2' => DRUPAL_ROOT . '/line2state.txt',
            '3' => DRUPAL_ROOT . '/line3state.txt'
        );
        $statuses = array();

        foreach ($status_files as $line => $path) {
            if (!is_file($path) || !is_readable($path)) {
                $statuses[$line] = 'STATUS FILE UNAVAILABLE';
                continue;
            }

            $report = @file_get_contents($path);
            if ($report === FALSE) {
                $statuses[$line] = 'STATUS READ ERROR';
                continue;
            }

            // Keep the caption readable and prevent an unexpectedly large report.
            $report = trim($report);
            $report = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', ' ', $report);
            $report = preg_replace('/\s+/', ' ', $report);
            $report = substr($report, 0, 240);
            $statuses[$line] = ($report === '') ? 'NO STATUS DATA' : $report;
        }

        print drupal_json_encode(array(
            'ok' => TRUE,
            'statuses' => $statuses,
            'updated' => REQUEST_TIME
        ));
        exit;
    }

    /* Command endpoint. Only allow the fixed command list above. */
    $command = isset($_POST['hssp_command']) ? trim((string) $_POST['hssp_command']) : '';

    if (!in_array($command, $hssp_commands, TRUE)) {
        print drupal_json_encode(array(
            'ok' => FALSE,
            'message' => 'Unknown command.'
        ));
        exit;
    }

    $saved = @file_put_contents($hssp_file, $command, LOCK_EX);

    if ($saved === FALSE) {
        print drupal_json_encode(array(
            'ok' => FALSE,
            'message' => 'Cannot write 2r.txt. Check server permissions.'
        ));
        exit;
    }

    print drupal_json_encode(array(
        'ok' => TRUE,
        'command' => $command,
        'message' => 'Command sent successfully.'
    ));
    exit;
}
?>

<div id="hssp-3d-app">
<style type="text/css">
#hssp-3d-app {
    --hssp-blue: #16cfff;
    max-width: 780px; margin: 25px auto; padding: 20px; box-sizing: border-box;
    color: #e8f4ff; font-family: Arial, Helvetica, sans-serif;
    background: radial-gradient(ellipse at 50% 0%, #183445 0%, transparent 55%), linear-gradient(145deg, #161b22, #050609 75%);
    border: 1px solid #414c59; border-radius: 18px;
    box-shadow: 0 15px 35px rgba(0,0,0,.65), inset 0 1px 1px rgba(255,255,255,.10);
}
#hssp-3d-app * { box-sizing: border-box; }
#hssp-3d-app .hssp-header { text-align:center; padding:10px 8px 20px; border-bottom:1px solid #3a4651; }
#hssp-3d-app .hssp-header h2 { margin:0; color:#eaf9ff; font-size:28px; letter-spacing:5px; text-shadow:0 0 15px rgba(22,207,255,.35); }
#hssp-3d-app .hssp-subtitle { margin-top:9px; color:#8b9aa9; font-size:10px; letter-spacing:3px; }
#hssp-3d-app .hssp-status { display:flex; align-items:center; justify-content:center; gap:10px; flex-wrap:wrap; margin:18px 0; padding:12px; color:#a8bac9; background:#0c1117; border:1px solid #343e49; border-radius:8px; font-size:12px; }
#hssp-3d-app .hssp-led { width:9px; height:9px; display:inline-block; flex-shrink:0; border-radius:50%; background:#59636e; box-shadow:0 0 5px #59636e; }
#hssp-3d-app .hssp-led.active { background:#19e6ff; box-shadow:0 0 8px #19e6ff, 0 0 18px #0785ff; }
#hssp-3d-app .hssp-led.error { background:#ff475e; box-shadow:0 0 9px #ff475e; }
#hssp-3d-app .hssp-lines { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; }
#hssp-3d-app .hssp-channel { min-width:0; padding:13px 9px 15px; background:linear-gradient(145deg,#303740,#171b21); border:1px solid #56606c; border-radius:11px; box-shadow:0 7px 0 #080a0e,0 9px 14px rgba(0,0,0,.6),inset 0 1px 1px rgba(255,255,255,.13); }
#hssp-3d-app .hssp-channel-title { margin-bottom:13px; text-align:center; color:#98adbc; font-size:12px; font-weight:bold; letter-spacing:2px; }
#hssp-3d-app .hssp-device { height:95px; position:relative; margin:0 auto 16px; max-width:150px; background:linear-gradient(130deg,#343b45 0%,#20252c 38%,#11151a 100%); border:2px solid #080a0e; border-radius:8px; box-shadow:inset 2px 2px 4px rgba(255,255,255,.08),inset -3px -4px 7px rgba(0,0,0,.7),0 2px 0 #59626d; }
#hssp-3d-app .hssp-device:before { content:""; position:absolute; top:9px; left:12%; right:12%; height:3px; background:#424d59; border-radius:3px; }
#hssp-3d-app .hssp-trigger { position:absolute; top:27px; left:23%; width:54%; height:5px; background:#13cfff; border-radius:5px; box-shadow:0 0 5px #13cfff,0 0 12px rgba(19,207,255,.8),0 0 22px rgba(19,207,255,.3); transition:all .2s ease; }
#hssp-3d-app .hssp-device.is-on .hssp-trigger { background:#a2f4ff; box-shadow:0 0 8px #13cfff,0 0 22px #13cfff,0 0 35px rgba(19,207,255,.8); }
#hssp-3d-app .hssp-device.is-off .hssp-trigger { background:#344f5b; box-shadow:0 0 4px rgba(19,207,255,.3); }
#hssp-3d-app .hssp-device-label { position:absolute; left:0; right:0; bottom:13px; text-align:center; color:#778590; font-size:9px; letter-spacing:2px; }
#hssp-3d-app .hssp-actions { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
#hssp-3d-app .hssp-btn { min-width:0; position:relative; padding:13px 5px; color:#dceaf5; font-size:12px; font-weight:bold; letter-spacing:1px; cursor:pointer; border-radius:7px; border:1px solid #68737e; background:linear-gradient(145deg,#525c67,#252a31); box-shadow:0 5px 0 #101318,0 7px 9px rgba(0,0,0,.55),inset 0 1px 1px rgba(255,255,255,.17); transition:transform .12s ease,box-shadow .12s ease; }
#hssp-3d-app .hssp-btn:before { content:""; display:block; height:3px; margin:-2px auto 9px; width:60%; background:#27343d; border-radius:3px; box-shadow:0 0 3px #27343d; }
#hssp-3d-app .hssp-btn-on:before { background:#1bd8ff; box-shadow:0 0 6px #1bd8ff,0 0 12px rgba(27,216,255,.55); }
#hssp-3d-app .hssp-btn-off:before { background:#738493; box-shadow:0 0 5px rgba(115,132,147,.45); }
#hssp-3d-app .hssp-btn:hover { border-color:#17cfff; color:#fff; }
#hssp-3d-app .hssp-btn:active,#hssp-3d-app .hssp-btn.pressed { transform:translateY(4px); box-shadow:0 1px 0 #101318,inset 0 2px 5px rgba(0,0,0,.6); }
#hssp-3d-app .hssp-btn:focus-visible { outline:2px solid #36dcff; outline-offset:3px; }
/* Live file-report caption shown directly beneath each ON/OFF row. */
#hssp-3d-app .hssp-live-status { margin-top:17px; padding:10px 8px; min-height:86px; text-align:center; background:linear-gradient(180deg,#111820,#090d12); border:1px solid #3e505d; border-radius:7px; box-shadow:inset 0 1px 5px rgba(0,0,0,.7); }
#hssp-3d-app .hssp-live-caption { color:#9bb1c0; font-size:9px; font-weight:bold; letter-spacing:1.5px; }
#hssp-3d-app .hssp-live-file { margin-top:5px; color:#5e899e; font-family:monospace; font-size:9px; overflow-wrap:anywhere; }
#hssp-3d-app .hssp-report-value { margin-top:8px; min-height:18px; color:#7fe8ff; font-family:monospace; font-size:11px; line-height:1.4; overflow-wrap:anywhere; text-shadow:0 0 7px rgba(19,207,255,.22); }
#hssp-3d-app .hssp-report-value.status-error { color:#ff929e; text-shadow:none; }
#hssp-3d-app .hssp-report-value.status-good { color:#8dffc0; }
#hssp-3d-app .hssp-manual { margin-top:28px; padding:16px; background:rgba(5,9,14,.7); border:1px solid #394550; border-radius:10px; }
#hssp-3d-app .hssp-manual h3 { margin:0 0 12px; font-size:12px; letter-spacing:2px; color:#9ab0bf; }
#hssp-3d-app .hssp-manual input { width:100%; padding:13px; color:#b9f4ff; background:#101820; border:1px solid #3c6575; border-radius:6px; font-family:monospace; font-size:15px; outline:none; }
#hssp-3d-app .hssp-manual input:focus { border-color:#13cfff; box-shadow:0 0 8px rgba(19,207,255,.25); }
#hssp-3d-app .hssp-manual button { margin-top:11px; width:100%; }
#hssp-3d-app .hssp-footer { padding-top:21px; text-align:center; color:#647584; font-size:9px; letter-spacing:2px; }
@media(max-width:520px) {
    #hssp-3d-app { padding:13px; margin:12px auto; }
    #hssp-3d-app .hssp-lines { gap:7px; }
    #hssp-3d-app .hssp-channel { padding:11px 6px 13px; }
    #hssp-3d-app .hssp-channel-title { font-size:10px; letter-spacing:1px; }
    #hssp-3d-app .hssp-device { height:76px; }
    #hssp-3d-app .hssp-btn { font-size:10px; letter-spacing:0; padding:11px 3px; }
    #hssp-3d-app .hssp-live-status { padding:8px 4px; }
    #hssp-3d-app .hssp-report-value { font-size:10px; }
}
@media(prefers-reduced-motion:reduce) { #hssp-3d-app *,#hssp-3d-app *:before { transition:none !important; } }
</style>

<div class="hssp-header">
    <h2>HSSP CONTROL</h2>
    <div class="hssp-subtitle">3D SMART AUTOMATION INTERFACE</div>
</div>

<div class="hssp-status" role="status" aria-live="polite">
    <span id="hssp-led" class="hssp-led"></span>
    <span id="hssp-status-text">SYSTEM READY</span>
    <span>|</span>
    <span>CMD: <strong id="hssp-current-command">iddle</strong></span>
</div>

<div class="hssp-lines">
    <div class="hssp-channel">
        <div class="hssp-channel-title">LINE 01</div>
        <div id="hssp-device-1" class="hssp-device"><div class="hssp-trigger"></div><div class="hssp-device-label">OUTPUT 01</div></div>
        <div class="hssp-actions">
            <button type="button" class="hssp-btn hssp-btn-on" data-command="line1on" data-line="1" data-state="on">ON</button>
            <button type="button" class="hssp-btn hssp-btn-off" data-command="line1off" data-line="1" data-state="off">OFF</button>
        </div>
        <div class="hssp-live-status" aria-live="polite">
            <div class="hssp-live-caption">LINE 1 LIVE STATUS</div>
            <div class="hssp-live-file">/ufo/line1state.txt</div>
            <div id="hssp-report-value-1" class="hssp-report-value">Loading status...</div>
        </div>
    </div>

    <div class="hssp-channel">
        <div class="hssp-channel-title">LINE 02</div>
        <div id="hssp-device-2" class="hssp-device"><div class="hssp-trigger"></div><div class="hssp-device-label">OUTPUT 02</div></div>
        <div class="hssp-actions">
            <button type="button" class="hssp-btn hssp-btn-on" data-command="line2on" data-line="2" data-state="on">ON</button>
            <button type="button" class="hssp-btn hssp-btn-off" data-command="line2off" data-line="2" data-state="off">OFF</button>
        </div>
        <div class="hssp-live-status" aria-live="polite">
            <div class="hssp-live-caption">LINE 2 LIVE STATUS</div>
            <div class="hssp-live-file">/ufo/line2state.txt</div>
            <div id="hssp-report-value-2" class="hssp-report-value">Loading status...</div>
        </div>
    </div>

    <div class="hssp-channel">
        <div class="hssp-channel-title">LINE 03</div>
        <div id="hssp-device-3" class="hssp-device"><div class="hssp-trigger"></div><div class="hssp-device-label">OUTPUT 03</div></div>
        <div class="hssp-actions">
            <button type="button" class="hssp-btn hssp-btn-on" data-command="line3on" data-line="3" data-state="on">ON</button>
            <button type="button" class="hssp-btn hssp-btn-off" data-command="line3off" data-line="3" data-state="off">OFF</button>
        </div>
        <div class="hssp-live-status" aria-live="polite">
            <div class="hssp-live-caption">LINE 3 LIVE STATUS</div>
            <div class="hssp-live-file">/ufo/line3state.txt</div>
            <div id="hssp-report-value-3" class="hssp-report-value">Loading status...</div>
        </div>
    </div>
</div>

<div class="hssp-manual">
    <h3>MANUAL COMMAND ENTRY</h3>
    <form id="hssp-manual-form">
        <input type="text" id="hssp-code-input" maxlength="256" autocomplete="off" placeholder="Enter an allowed command..." aria-label="Automation command">
        <button class="hssp-btn hssp-btn-on" type="submit">SEND COMMAND</button>
    </form>
    <p style="font-size:11px;color:#7e92a1;line-height:1.5;">Allowed: line1on, line1off, line2on, line2off, line3on, line3off, iddle.</p>
</div>
<div class="hssp-footer">HSSP • SMART CONTROL TERMINAL • LIVE REPORTING</div>

<script type="text/javascript">
(function () {
    'use strict';
    var app = document.getElementById('hssp-3d-app');
    if (!app) return;

    var token = <?php print drupal_json_encode($hssp_token); ?>;
    var allowed = ['line1on','line1off','line2on','line2off','line3on','line3off','iddle'];
    var statusText = document.getElementById('hssp-status-text');
    var currentCommand = document.getElementById('hssp-current-command');
    var led = document.getElementById('hssp-led');
    var idleTimer = null;
    var requestNumber = 0;
    var busy = false;

    function showStatus(message, type) {
        statusText.textContent = message;
        led.className = 'hssp-led' + (type === 'ok' ? ' active' : (type === 'error' ? ' error' : ''));
    }

    function updateDisplay(command) {
        var match = /^line([123])(on|off)$/.exec(command);
        if (!match) return;
        var device = document.getElementById('hssp-device-' + match[1]);
        if (device) {
            device.classList.toggle('is-on', match[2] === 'on');
            device.classList.toggle('is-off', match[2] === 'off');
        }
    }

    function postAjax(fields) {
        var body = new URLSearchParams();
        Object.keys(fields).forEach(function (key) { body.append(key, fields[key]); });
        return fetch(window.location.href, {
            method: 'POST',
            credentials: 'same-origin',
            cache: 'no-store',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                'Accept': 'application/json'
            },
            body: body.toString()
        }).then(function (response) {
            return response.text();
        }).then(function (text) {
            try { return JSON.parse(text); }
            catch (error) { throw new Error('Invalid server response. Check Drupal PHP Filter and page permissions.'); }
        });
    }

    function sendCommand(command, scheduleIdle) {
        command = String(command || '').trim();
        if (allowed.indexOf(command) === -1) {
            showStatus('COMMAND NOT ALLOWED', 'error');
            return Promise.reject(new Error('Command not allowed'));
        }
        if (idleTimer) { clearTimeout(idleTimer); idleTimer = null; }

        var thisRequest = ++requestNumber;
        busy = true;
        showStatus('SENDING COMMAND...', '');
        currentCommand.textContent = command;

        return postAjax({hssp_ajax:'1', hssp_action:'command', hssp_token:token, hssp_command:command})
        .then(function (result) {
            if (!result.ok) throw new Error(result.message || 'Command failed.');
            if (thisRequest !== requestNumber) return result;
            currentCommand.textContent = result.command;
            showStatus('COMMAND SENT SUCCESSFULLY', 'ok');
            updateDisplay(command);
            if (scheduleIdle && command !== 'iddle') {
                idleTimer = setTimeout(function () {
                    sendCommand('iddle', false).catch(function () { showStatus('IDLE RESET FAILED', 'error'); });
                }, 6000);
            }
            return result;
        })
        .catch(function (error) {
            if (thisRequest === requestNumber) showStatus(error.message || 'CONNECTION FAILED', 'error');
            throw error;
        })
        .then(function (result) {
            if (thisRequest === requestNumber) busy = false;
            return result;
        }, function (error) {
            if (thisRequest === requestNumber) busy = false;
            throw error;
        });
    }

    function renderReport(line, value) {
        var element = document.getElementById('hssp-report-value-' + line);
        if (!element) return;
        element.textContent = value || 'NO STATUS DATA';
        element.classList.remove('status-error', 'status-good');
        if (/UNAVAILABLE|ERROR|FAILED/i.test(element.textContent)) {
            element.classList.add('status-error');
        } else if (/\bON\b|ONLINE|READY|ACTIVE/i.test(element.textContent)) {
            element.classList.add('status-good');
        }
    }

    /* Status reports are read from the published HTTPS text files. */
    var statusUrls = {
        '1': 'https://yoursite.com/ufo/line1state.txt',
        '2': 'https://yoursite.com/ufo/line2state.txt',
        '3': 'https://yoursite.com/ufo/line3state.txt'
    };

    function refreshOneStatus(line) {
        var url = statusUrls[line];
        // Cache-busting query plus no-store prevents stale text-file reports.
        var separator = url.indexOf('?') === -1 ? '?' : '&';
        var requestUrl = url + separator + '_hssp=' + new Date().getTime();

        return fetch(requestUrl, {
            method: 'GET',
            cache: 'no-store',
            credentials: 'omit',
            headers: { 'Accept': 'text/plain, */*' }
        }).then(function (response) {
            if (!response.ok) {
                throw new Error('HTTP ' + response.status);
            }
            return response.text();
        }).then(function (report) {
            // Display as plain text, not HTML, to keep file contents safe.
            report = String(report || '').replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ' ');
            report = report.replace(/\s+/g, ' ').trim().substring(0, 240);
            renderReport(line, report || 'NO STATUS DATA');
        }).catch(function () {
            renderReport(line, 'STATUS FILE UNAVAILABLE');
        });
    }

    function refreshStatuses() {
        refreshOneStatus('1');
        refreshOneStatus('2');
        refreshOneStatus('3');
    }

    app.querySelectorAll('[data-command]').forEach(function (button) {
        button.addEventListener('click', function () {
            if (busy) { showStatus('PLEASE WAIT...', ''); return; }
            button.classList.add('pressed');
            setTimeout(function () { button.classList.remove('pressed'); }, 180);
            sendCommand(button.getAttribute('data-command'), true).catch(function () {});
        });
    });

    var manualForm = document.getElementById('hssp-manual-form');
    var manualInput = document.getElementById('hssp-code-input');
    manualForm.addEventListener('submit', function (event) {
        event.preventDefault();
        if (busy) { showStatus('PLEASE WAIT...', ''); return; }
        var command = manualInput.value.trim();
        sendCommand(command, true).then(function () { manualInput.value = ''; }).catch(function () {});
    });

    // Read the three status files immediately, then refresh every 3 seconds.
    refreshStatuses();
    window.setInterval(refreshStatuses, 3000);
})();
</script>
</div>
FALSE, 'message' => 'Invalid security token. Reload the page.' )); exit; } $action = isset($_POST['hssp_action']) ? (string) $_POST['hssp_action'] : 'command'; /* Read all three status text files. This request does not write 2r.txt. */ if ($action === 'status') { $status_files = array( '1' => DRUPAL_ROOT . '/line1state.txt', '2' => DRUPAL_ROOT . '/line2state.txt', '3' => DRUPAL_ROOT . '/line3state.txt' ); $statuses = array(); foreach ($status_files as $line => $path) { if (!is_file($path) || !is_readable($path)) { $statuses[$line] = 'STATUS FILE UNAVAILABLE'; continue; } $report = @file_get_contents($path); if ($report === FALSE) { $statuses[$line] = 'STATUS READ ERROR'; continue; } // Keep the caption readable and prevent an unexpectedly large report. $report = trim($report); $report = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', ' ', $report); $report = preg_replace('/\s+/', ' ', $report); $report = substr($report, 0, 240); $statuses[$line] = ($report === '') ? 'NO STATUS DATA' : $report; } print drupal_json_encode(array( 'ok' => TRUE, 'statuses' => $statuses, 'updated' => REQUEST_TIME )); exit; } /* Command endpoint. Only allow the fixed command list above. */ $command = isset($_POST['hssp_command']) ? trim((string) $_POST['hssp_command']) : ''; if (!in_array($command, $hssp_commands, TRUE)) { print drupal_json_encode(array( 'ok' => FALSE, 'message' => 'Unknown command.' )); exit; } $saved = @file_put_contents($hssp_file, $command, LOCK_EX); if ($saved === FALSE) { print drupal_json_encode(array( 'ok' => FALSE, 'message' => 'Cannot write 2r.txt. Check server permissions.' )); exit; } print drupal_json_encode(array( 'ok' => TRUE, 'command' => $command, 'message' => 'Command sent successfully.' )); exit; } ?>

HSSP CONTROL

3D SMART AUTOMATION INTERFACE
SYSTEM READY | CMD: iddle
LINE 01
OUTPUT 01
LINE 1 LIVE STATUS
/ufo/line1state.txt
Loading status...
LINE 02
OUTPUT 02
LINE 2 LIVE STATUS
/ufo/line2state.txt
Loading status...
LINE 03
OUTPUT 03
LINE 3 LIVE STATUS
/ufo/line3state.txt
Loading status...

MANUAL COMMAND ENTRY

Allowed: line1on, line1off, line2on, line2off, line3on, line3off, iddle.