{"id":548,"date":"2025-09-23T14:13:50","date_gmt":"2025-09-23T12:13:50","guid":{"rendered":"http:\/\/sbfishing.fi\/?page_id=548"},"modified":"2025-09-23T14:13:51","modified_gmt":"2025-09-23T12:13:51","slug":"678-2","status":"publish","type":"page","link":"https:\/\/sbfishing.fi\/index.php\/678-2\/","title":{"rendered":""},"content":{"rendered":"\n<!doctype html>\n<html lang=\"fi\">\n<meta charset=\"utf-8\" \/>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" \/>\n<title>SB TrollPilot \u2013 Aktivointi (DEMO)<\/title>\n\n<style>\n  :root { font-family: system-ui, Arial, sans-serif; }\n  body { max-width: 720px; margin: 24px auto; padding: 0 16px; }\n  h1 { margin: 0 0 12px; }\n  .card { border: 1px solid #ddd; border-radius: 10px; padding: 16px; margin: 12px 0; }\n  button { padding: 10px 14px; border-radius: 8px; border: 1px solid #999; cursor: pointer; }\n  button:disabled { opacity: .5; cursor: not-allowed; }\n  .row { display: flex; gap: 8px; flex-wrap: wrap; }\n  pre { background: #f7f7f7; padding: 12px; border-radius: 8px; overflow: auto; }\n  .ok { color: #0a0; font-weight: 600; }\n  .err { color: #a00; font-weight: 600; }\n  .kv { display: grid; grid-template-columns: 140px 1fr; gap: 6px 12px; }\n  .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }\n<\/style>\n\n<h1>SB TrollPilot \u2013 Aktivointi (DEMO)<\/h1>\n<p>T\u00e4m\u00e4 on pelkk\u00e4 testisivu BLE-yhteyden kokeiluun. Se lukee laitteesta <b>DeviceID<\/b> ja <b>Challenge<\/b> ja l\u00e4hett\u00e4\u00e4 demona\nlisenssikentt\u00e4\u00e4n tekstin <span class=\"mono\">DEBUG_OK<\/span>, jonka firmware hyv\u00e4ksyy ja tallentaa.<\/p>\n\n<div class=\"card\">\n  <div class=\"row\">\n    <button id=\"btnConnect\">Yhdist\u00e4 laitteeseen<\/button>\n    <button id=\"btnRefresh\" disabled>P\u00e4ivit\u00e4 ID &amp; Challenge<\/button>\n    <button id=\"btnActivate\" disabled>Aktivoi (DEMO)<\/button>\n  <\/div>\n  <div id=\"status\" style=\"margin-top:10px\"><\/div>\n<\/div>\n\n<div class=\"card\">\n  <h3>Yhteenveto<\/h3>\n  <div class=\"kv\">\n    <div>Laitenimi:<\/div><div id=\"devName\" class=\"mono\">\u2013<\/div>\n    <div>DeviceID:<\/div><div id=\"devId\" class=\"mono\">\u2013<\/div>\n    <div>Challenge:<\/div><div id=\"devChall\" class=\"mono\">\u2013<\/div>\n    <div>Status (notify):<\/div><div id=\"devNotify\" class=\"mono\">\u2013<\/div>\n  <\/div>\n<\/div>\n\n<div class=\"card\">\n  <h3>Lokit<\/h3>\n  <pre id=\"log\"><\/pre>\n<\/div>\n\n<script>\n\/* ===== UUID:t \u2013 samat kuin firmiksess\u00e4 ===== *\/\nconst SERVICE      = \"12345678-1234-1234-1234-1234567890ab\";\nconst CHAR_ID      = \"12345678-1234-1234-1234-1234567890ac\";\nconst CHAR_CHALL   = \"12345678-1234-1234-1234-1234567890ad\";\nconst CHAR_WRITE   = \"12345678-1234-1234-1234-1234567890ae\";\nconst CHAR_STATUS  = \"12345678-1234-1234-1234-1234567890af\";\n\nlet device, server, service;\nlet cId, cChall, cWrite, cStatus;\n\nconst $ = sel => document.querySelector(sel);\nconst log = (s) => { const el = $(\"#log\"); el.textContent += s + \"\\n\"; el.scrollTop = el.scrollHeight; };\nconst set = (id, val) => { $(id).textContent = val; };\n\nasync function connect() {\n  try {\n    $(\"#status\").textContent = \"\";\n    device = await navigator.bluetooth.requestDevice({\n      filters: [{ services: [SERVICE] }],\n      optionalServices: [SERVICE]\n    });\n    set(\"#devName\", device.name || \"(nimi puuttuu)\");\n    log(\"Valittu laite: \" + (device.name || \"(nimi puuttuu)\"));\n\n    server = await device.gatt.connect();\n    service = await server.getPrimaryService(SERVICE);\n\n    cId     = await service.getCharacteristic(CHAR_ID);\n    cChall  = await service.getCharacteristic(CHAR_CHALL);\n    cWrite  = await service.getCharacteristic(CHAR_WRITE);\n    cStatus = await service.getCharacteristic(CHAR_STATUS);\n\n    \/\/ Status-notify p\u00e4\u00e4lle\n    try {\n      await cStatus.startNotifications();\n      cStatus.addEventListener(\"characteristicvaluechanged\", (e) => {\n        const t = new TextDecoder().decode(e.target.value);\n        set(\"#devNotify\", t);\n        log(\"STATUS notify: \" + t);\n        if (t && t.toUpperCase().includes(\"OK\")) {\n          $(\"#status\").innerHTML = '<span class=\"ok\">Lisenssi hyv\u00e4ksytty (DEMO)<\/span>';\n          $(\"#btnActivate\").disabled = true;\n        }\n      });\n      log(\"Status-notifications aktivoitu.\");\n    } catch (e) {\n      log(\"Status-notifications ep\u00e4onnistui: \" + e);\n    }\n\n    await refresh();\n    $(\"#btnActivate\").disabled = false;\n    $(\"#btnRefresh\").disabled = false;\n  } catch (e) {\n    log(\"Virhe yhdist\u00e4ess\u00e4: \" + e);\n    $(\"#status\").innerHTML = '<span class=\"err\">Yhdist\u00e4minen ep\u00e4onnistui: ' + e + '<\/span>';\n  }\n}\n\nasync function refresh() {\n  try {\n    const idVal = new TextDecoder().decode(await cId.readValue());\n    const chVal = new TextDecoder().decode(await cChall.readValue());\n    set(\"#devId\", idVal);\n    set(\"#devChall\", chVal);\n    log(\"DeviceID: \" + idVal);\n    log(\"Challenge: \" + chVal);\n  } catch (e) {\n    log(\"Lukuvirhe: \" + e);\n  }\n}\n\nasync function activateDemo() {\n  try {\n    const payload = new TextEncoder().encode(\"DEBUG_OK\");\n    await cWrite.writeValue(payload);\n    log(\"Kirjoitettu DEBUG_OK lisenssikentt\u00e4\u00e4n.\");\n    $(\"#status\").textContent = \"Odotetaan STATUS-notifyt\u00e4...\";\n  } catch (e) {\n    log(\"Kirjoitusvirhe: \" + e);\n    $(\"#status\").innerHTML = '<span class=\"err\">Kirjoitus ep\u00e4onnistui: ' + e + '<\/span>';\n  }\n}\n\n$(\"#btnConnect\").onclick = connect;\n$(\"#btnRefresh\").onclick = refresh;\n$(\"#btnActivate\").onclick = activateDemo;\n\n\/* Pieni tuki-ilmoitus jos selain ei tue Web Bluetoothia *\/\nif (!navigator.bluetooth) {\n  $(\"#status\").innerHTML = '<span class=\"err\">Selaimesi ei tue Web Bluetoothia. Kokeile Chrome\/Edge (https tai localhost).<\/span>';\n}\n<\/script>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>SB TrollPilot \u2013 Aktivointi (DEMO) SB TrollPilot \u2013 Aktivointi (DEMO) T\u00e4m\u00e4 on pelkk\u00e4 testisivu BLE-yhteyden kokeiluun. Se lukee laitteesta DeviceID ja Challenge ja l\u00e4hett\u00e4\u00e4 demona lisenssikentt\u00e4\u00e4n tekstin DEBUG_OK, jonka firmware hyv\u00e4ksyy ja tallentaa. Yhdist\u00e4 laitteeseen P\u00e4ivit\u00e4 ID &amp; Challenge Aktivoi (DEMO) Yhteenveto Laitenimi: \u2013 DeviceID: \u2013 Challenge: \u2013 Status (notify): \u2013 Lokit<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"_links":{"self":[{"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/pages\/548"}],"collection":[{"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/comments?post=548"}],"version-history":[{"count":1,"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/pages\/548\/revisions"}],"predecessor-version":[{"id":549,"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/pages\/548\/revisions\/549"}],"wp:attachment":[{"href":"https:\/\/sbfishing.fi\/index.php\/wp-json\/wp\/v2\/media?parent=548"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}