diff --git a/api/mqtt_listener.php b/api/mqtt_listener.php index 5e33ae6..7ff97ee 100644 --- a/api/mqtt_listener.php +++ b/api/mqtt_listener.php @@ -59,7 +59,7 @@ $db = new PDO( /* ========================= * MQTT CONFIG * ========================= */ -$mqttHost = 'mqtt.xupas.mywire.org'; +$mqttHost = '192.168.10.106'; // CT106: broker com a frota TODA (bridge VPS esp/+/status both) $mqttUser = 'xupa'; $mqttPass = 'xupa'; @@ -73,6 +73,7 @@ $tlsSettings = (new ConnectionSettings()) ->setPassword($mqttPass) ->setUseTls(true) ->setTlsSelfSignedAllowed(true) + ->setTlsVerifyPeerName(false) ->setKeepAliveInterval(30) ->setConnectTimeout(5) ->setSocketTimeout(1) @@ -107,6 +108,8 @@ $subscribeTls = function () use ($mqttTls, $db, $deviceSecret) { $rssi = isset($json['rssi']) ? (int)$json['rssi'] : null; $broker = isset($json['broker']) ? (string)$json['broker'] : null; $brightness = isset($json['brightness']) ? (int)$json['brightness'] : null; + $fw = isset($json['fw']) ? (string)$json['fw'] : null; + $chip = isset($json['chip']) ? (string)$json['chip'] : null; $hmac = isset($json['hmac']) ? strtoupper((string)$json['hmac']) : null; if ($hmac === null || $uptime === null) { @@ -114,7 +117,11 @@ $subscribeTls = function () use ($mqttTls, $db, $deviceSecret) { return; } - $expected = strtoupper(hash_hmac('sha256', $uid . '|' . $uptime, $deviceSecret)); + $_m = $uid . '|' . $uptime; + $_eg = strtoupper(hash_hmac('sha256', $_m, $deviceSecret)); // global + $_dsec = hash_hmac('sha256', $uid, 'af2e8f1b5411d7df7c9b3dba45fa4ca4517329d28d2550d29be898d34b015952'); + $_ed = strtoupper(hash_hmac('sha256', $_m, $_dsec)); // Fase C por-device + $expected = hash_equals($_ed, (string)$hmac) ? $_ed : $_eg; // aceita global OU per-device if (!hash_equals($expected, $hmac)) { logmsg("STATUS HMAC INVÁLIDO $uid — ignorado", LOG_ERROR); @@ -124,10 +131,10 @@ $subscribeTls = function () use ($mqttTls, $db, $deviceSecret) { $stmt = $db->prepare(" INSERT INTO contadores (uid, entradas, saidas, entradas_total, saidas_total, last_seen, online, - uptime, heap, rssi, current_broker, brightness) + uptime, heap, rssi, current_broker, brightness, fw_ver, chip) VALUES (:uid, 0, 0, 0, 0, NOW(), 1, - :uptime, :heap, :rssi, :broker, :brightness) + :uptime, :heap, :rssi, :broker, :brightness, :fw, :chip) ON DUPLICATE KEY UPDATE last_seen=NOW(), online=1, @@ -135,7 +142,10 @@ $subscribeTls = function () use ($mqttTls, $db, $deviceSecret) { heap=COALESCE(:heap2, heap), rssi=COALESCE(:rssi2, rssi), current_broker=COALESCE(:broker2, current_broker), - brightness=COALESCE(:brightness2, brightness) + brightness=COALESCE(:brightness2, brightness), + fw_ver=COALESCE(:fw2, fw_ver), + chip=COALESCE(:chip2, chip), + auth_ok=IF(blocked=0,1,auth_ok) "); $stmt->execute([ 'uid' => $uid, @@ -149,12 +159,23 @@ $subscribeTls = function () use ($mqttTls, $db, $deviceSecret) { 'rssi2' => $rssi, 'broker2' => $broker, 'brightness2' => $brightness, + 'fw' => $fw, + 'fw2' => $fw, + 'chip' => $chip, + 'chip2' => $chip, ]); - $mqttTls->publish("esp/$uid/cmd", - json_encode(['cmd' => 'HEARTBEAT_OK']), 1, false); + $chk = $db->prepare("SELECT blocked FROM contadores WHERE uid=:uid"); + $chk->execute(['uid' => $uid]); + $row = $chk->fetch(PDO::FETCH_ASSOC); - logmsg("STATUS OK $uid uptime=$uptime heap=$heap rssi=$rssi broker=$broker → HEARTBEAT_OK"); + if (!$row || (int)($row['blocked'] ?? 0) === 0) { + $mqttTls->publish("esp/$uid/cmd", + json_encode(['cmd' => 'HEARTBEAT_OK']), 1, false); + logmsg("STATUS OK $uid uptime=$uptime heap=$heap rssi=$rssi broker=$broker → HEARTBEAT_OK"); + } else { + logmsg("STATUS BLOQUEADO $uid — sem HEARTBEAT_OK", LOG_ERROR); + } }, 0); diff --git a/api/ota_trigger.php b/api/ota_trigger.php new file mode 100644 index 0000000..71da943 --- /dev/null +++ b/api/ota_trigger.php @@ -0,0 +1,25 @@ +'url_required']); exit; } +if (!in_array($cmd, ['OTA_CHECK','OTA_URL'], true)) { http_response_code(400); echo json_encode(['error'=>'cmd_invalid']); exit; } + +$payload = json_encode(['cmd'=>$cmd,'url'=>$url], JSON_UNESCAPED_SLASHES); + +if ($uid === 'all') { + $rows = $pdo->query("SELECT uid FROM contadores WHERE blocked=0 AND online=1")->fetchAll(PDO::FETCH_ASSOC); + foreach ($rows as $r) mqtt_publish("esp/{$r['uid']}/cmd", $payload); + echo json_encode(['ok'=>1,'sent'=>count($rows)]); +} else { + if (!$uid) { http_response_code(400); echo json_encode(['error'=>'uid_required']); exit; } + mqtt_publish("esp/$uid/cmd", $payload); + echo json_encode(['ok'=>1]); +} diff --git a/esp_devices.php b/esp_devices.php new file mode 100644 index 0000000..f2475a3 --- /dev/null +++ b/esp_devices.php @@ -0,0 +1,137 @@ +true,CURLOPT_TIMEOUT=>8]); + $r = json_decode(curl_exec($ch),true); curl_close($ch); + return $r['devices'] ?? []; +} + +function pmx_post(array $data): array { + $ch = curl_init(PMX_API); + curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,CURLOPT_POSTFIELDS=>http_build_query($data),CURLOPT_TIMEOUT=>8]); + $r = json_decode(curl_exec($ch),true); curl_close($ch); + return $r ?? []; +} + +$notice = ''; $error = ''; + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $uid = preg_replace('/[^0-9A-Fa-f]/', '', $_POST['uid'] ?? ''); + if (!$uid) { $error = 'UID inválido.'; } + else { + $res = pmx_post($_POST); + if (!empty($res['ok'])) $notice = "[{$uid}] {$_POST['action']} OK"; + else $error = $res['error'] ?? 'Erro'; + } + $qs = $notice ? '?ok='.urlencode($notice) : ($error ? '?err='.urlencode($error) : ''); + header("Location: esp_devices.php$qs"); exit; +} + +if (isset($_GET['ok'])) $notice = htmlspecialchars($_GET['ok']); +if (isset($_GET['err'])) $error = htmlspecialchars($_GET['err']); + +$devices = pmx_get(); +function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES); } +?> + + +
+ + +Sem dispositivos ou erro a ligar ao broker Proxmox.
+ +| UID | Broker atual | Estado | Último contacto | Heap | RSSI | Ações |
|---|---|---|---|---|---|---|
| = h($uid) ?> | += h($broker) ?> | ++ bloqueado + + aprovado + | += h($last) ?> = $ago ?> |
+ = $d['heap'] ? number_format((int)$d['heap']) : '—' ?> | += $d['rssi'] ? $d['rssi'].' dBm' : '—' ?> | ++ + + + + + + + + + + + | +
Sem dispositivos ou erro a ligar ao broker Proxmox.
| UID | Versão | Versão | Ultimo contacto | Online | Estado | Brilho | Ações | Broker |
|---|---|---|---|---|---|---|---|---|
| = h($uid) ?> | = ($d['fw_ver']??'')!=='' ? h($d['fw_ver']) : '—' ?> | += h($d['fw_ver'] ?? '—') ?> | += h($last) ?> = $ago ?> |
+ onlineoffline | +bloqueadoaprovado | +
+ >
+ = $bri ?>
+ |
+ + + + + + + + + | ++ + + | +
Sem dispositivos ou erro a ligar a VPS.
| UID | Versão | Versão | Online | Estado | Ultimo contacto | Brilho | Broker | |
|---|---|---|---|---|---|---|---|---|
| = h($uid) ?> | = ($d['fw']??'')!=='' ? h($d['fw']) : '—' ?> | += h($d['fw_ver'] ?? '—') ?> | +onlineoffline | +bloqueadoaprovadopendente | += h($last) ?> = $ago ?> |
+
+
+ >
+ = $bri ?>
+
+ |
+ + + + + + + + + | ++ + + | +
| UID | Chip | Versao atual | Disponivel | Online | |
|---|---|---|---|---|---|
| = h($d['uid']) ?> | += h($chip ?? '—') ?> | ++ + = h($fw) ?> + — + | += $latest ? h($latest) : '—' ?> | +onlineoffline | ++ + + + | +
Bem-vindo, = h($_SESSION['username'] ?? '') ?>
+