summaryrefslogtreecommitdiffhomepage
path: root/index.html
blob: 13e455745deabcf66805111c6113668a0e0c1d67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<html>
    <head>
        <title>Setup AIRMX device</title>
    </head>
    <body>
        <h1>Setup your AIRMX device</h1>
        <div>
            <button id="connect" type="button">
                Connect
            </button>
        </div>
        <script>
            const DEVICE_NAME = 'AIRMX Pro'
            const MAIN_SERVICE_UUID = '22210000-554a-4546-5542-46534450464d'
            const WRITE_CHAR_UUID = '22210001-554a-4546-5542-46534450464d'
            const NOTIFY_CHAR_UUID = '22210002-554a-4546-5542-46534450464d'

            async function delay(ms) {
                return new Promise(resolve => setTimeout(resolve, ms))
            }

            async function connectToDevice() {
                const device = await navigator.bluetooth.requestDevice({
                    filters: [
                        { name: DEVICE_NAME }
                    ],
                    optionalServices: [MAIN_SERVICE_UUID]
                })

                const server = await device.gatt.connect()
                const service = await server.getPrimaryService(MAIN_SERVICE_UUID)

                const writeChar = await service.getCharacteristic(WRITE_CHAR_UUID)
                const notifyChar = await service.getCharacteristic(NOTIFY_CHAR_UUID)

                // 1. Enable notifications
                await notifyChar.startNotifications()
                notifyChar.addEventListener('characteristicvaluechanged', handleDeviceResponse)

                await delay(500)

                // 2. Send the first bind command
                await sendBindCommand(writeChar)
                await delay(500)

                // 3. Send Wi-Fi credentials
                const ssid = '<yourssid>'
                const password = '<yourpassword>'
                await sendWifiCredentialsCommand(writeChar, ssid, password)
                await delay(500)

                // 4. Retrieve device ID
                await sendRequestDeviceIdentityCommand(writeChar)
            }

            function handleDeviceResponse(event) {
                const value = event.target.value
                const receivedBytes = []
                for (let i = 0; i < value.byteLength; i++) {
                    receivedBytes.push(value.getUint8(i).toString(16).padStart(2, '0'))
                }
                console.log(`Received data from device: ${receivedBytes.join(' ')}`)
            }

            async function sendBindCommand(writeChar) {
                const handshakePacket = new Uint8Array([
                    // --- 4-byte Header ---
                    0x01, // Sequence Number: 1
                    0x11, // Packet Info: (Packet 1 of 1)
                    0x00, // Command ID: 11 (Big Endian Short, MSB)
                    0x0B, // Command ID: 11 (Big Endian Short, LSB)

                    // --- 15-byte Payload ---
                    0x08, // Hardcoded first byte of payload
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Token (as 0L)
                    0x05, // Length of version string "1.0.0"
                    0x31, 0x2e, 0x30, 0x2e, 0x30  // ASCII for "1.0.0"
                ])

                await sendRawData(writeChar, handshakePacket)
            }

            async function sendWifiCredentialsCommand(writeChar, ssid, password) {
                const encoder = new TextEncoder()
                const ssidBytes = encoder.encode(ssid)
                const passwordBytes = encoder.encode(password)

                const ssidLenSize = 1
                const ssidSize = ssidBytes.length
                const passwordLenSize = 1
                const passwordSize = passwordBytes.length
                const plaintextPayload = new Uint8Array(ssidLenSize + ssidSize + passwordLenSize + passwordSize)

                let offset = 0

                plaintextPayload[offset] = ssidSize
                offset++

                plaintextPayload.set(ssidBytes, offset)
                offset += ssidSize

                plaintextPayload[offset] = passwordSize
                offset++

                plaintextPayload.set(passwordBytes, offset)

                const packet1 = new Uint8Array([
                    // Header (4 bytes)
                    0x02, // Sequence Number: 2
                    0x12, // Packet Info: (Packet 1 of 2)
                    0x00, // Command ID: 21, Enc-Flag: 0 (Big Endian)
                    0x15,
                    ...plaintextPayload.slice(0, 16)
                ])

                const packet2 = new Uint8Array([
                    // Header (4 bytes)
                    0x03, // Sequence Number: 3
                    0x22, // Packet Info: (Packet 2 of 2)
                    0x00, // Command ID: 21, Enc-Flag: 0 (Big Endian)
                    0x15,
                    ...plaintextPayload.slice(16)
                ])

                console.log('Sending Wi-Fi credentials packet 1/2...')
                await sendRawData(writeChar, packet1)
                await delay(100)

                console.log('Sending Wi-Fi credentials packet 2/2...')
                await sendRawData(writeChar, packet2)
            }

            async function sendRequestDeviceIdentityCommand(writeChar) {
                const packet = new Uint8Array([
                    // Header (4 bytes)
                    0x04, // Sequence Number: 4
                    0x11, // Packet Info: (Packet 1 of 1)
                    0x00, // Command ID: 22, Enc-Flag: 0 (Big Endian)
                    0x16
                ])

                await sendRawData(writeChar, packet)
            }

            async function sendRawData(characteristic, data) {
                const chunkSize = 20
                for (let i = 0; i < data.length; i += chunkSize) {
                    const chunk = data.slice(i, i + chunkSize)
                    console.log(`Sending chunk: ${Array.from(chunk).map(b => b.toString(16).padStart(2, '0')).join(' ')}`)
                    await characteristic.writeValueWithResponse(chunk)
                }
            }

            const connect = document.getElementById('connect')
            connect.addEventListener('click', connectToDevice)
        </script>
    </body>
</html>