Sending time requests over UDP or TCP
Send a packet to the BBTime server to receive the current time. The same port accepts both transports: UDP is the normal path, and TCP is the fallback for devices that never see the UDP reply. The packet format and the response are identical on both.
The first two bytes identify the device, the rest is the device-specific payload (e.g. trigger data) or zero padding:
| Bytes | Description |
|---|---|
| 0-1 |
BB device ID, 2 bytes big-endian
(e.g. 0x2300-0x23FF for monitoring devices)
|
| 2+ |
Device payload (e.g. frame_id, bb_status, trigger data) or zero padding
|
Response format (29 bytes), the same on UDP and TCP:
+CCLK: "YY/MM/DD,HH:MM:SS+ZZ"
| Transport | When to use it | Minimum packet size |
|---|---|---|
| UDP | Normal path. Send the packet, read the reply. | 29 bytes — shorter packets are dropped to prevent amplification attacks |
| TCP | Fallback when UDP replies don't arrive. Connect, send the same packet, read the reply on the connection; the server then closes it. | 4 bytes — no minimum size beyond the header, since the TCP handshake already rules out spoofing |
Rate limit: 20 responses per minute per BB device, counted across both transports.
When to use the TCP fallback: some mobile carriers behind CGNAT drop the UDP NAT mapping before the reply gets back, so the device never receives the time. On those networks, retry over TCP on the same host and port — the connection keeps the mapping open, so the reply gets through. Devices should try UDP first and fall back to TCP only after a short timeout with no reply.
Linux (netcat/bash)
# 65-byte trigger packet from BB ID 0x2300 (bytes 0-1).
# To use a different BB device, change bytes 1-2 — the high byte (\x23)
# selects monitoring-device family, the low byte is the device instance.
printf '\x23\x00\x01\xff\x00\x77\xff\x45\x05\x00\x19\x37\x12\x34\x56\x78\x90\x12\x23\x25\x58\x42\x16\x92\x02\x01\x00\x01\x20\x1f\x00\xff\xff\x00\x00\x00\x00\x72\x41\x29\x01\x10\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | nc -u -w1 bbtime.bbserver.eu 4444
# Same packet via socat
printf '\x23\x00\x01\xff\x00\x77\xff\x45\x05\x00\x19\x37\x12\x34\x56\x78\x90\x12\x23\x25\x58\x42\x16\x92\x02\x01\x00\x01\x20\x1f\x00\xff\xff\x00\x00\x00\x00\x72\x41\x29\x01\x10\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | socat - UDP:bbtime.bbserver.eu:4444
Linux (TCP fallback)
# If UDP replies never arrive (e.g. behind CGNAT), send the same packet
# over TCP on the same port — drop -u and the server replies on the
# connection, then closes it.
printf '\x23\x00\x01\xff\x00\x77\xff\x45\x05\x00\x19\x37\x12\x34\x56\x78\x90\x12\x23\x25\x58\x42\x16\x92\x02\x01\x00\x01\x20\x1f\x00\xff\xff\x00\x00\x00\x00\x72\x41\x29\x01\x10\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | nc -w2 bbtime.bbserver.eu 4444
macOS (netcat)
# macOS netcat requires -c to close after response.
# Edit bytes 1-2 ('\x23\x00') to set your BB ID.
printf '\x23\x00\x01\xff\x00\x77\xff\x45\x05\x00\x19\x37\x12\x34\x56\x78\x90\x12\x23\x25\x58\x42\x16\x92\x02\x01\x00\x01\x20\x1f\x00\xff\xff\x00\x00\x00\x00\x72\x41\x29\x01\x10\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | nc -u -w1 -c bbtime.bbserver.eu 4444
Windows (PowerShell)
$udp = New-Object System.Net.Sockets.UdpClient
# 65-byte trigger packet from BB ID 0x2300.
# Change bytes [0] and [1] to set your BB ID.
$bytes = [byte[]]@(
0x23, 0x00, 0x01, 0xFF,
0x00, 0x77, 0xFF, 0x45, 0x05, 0x00, 0x19, 0x37,
0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
0x23, 0x25, 0x58, 0x42, 0x16, 0x92,
0x02, 0x01, 0x00, 0x01, 0x20, 0x1F, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x72, 0x41, 0x29, 0x01, 0x10,
0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
)
$udp.Send($bytes, $bytes.Length, "bbtime.bbserver.eu", 4444)
# Receive time response
$ep = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0)
$response = $udp.Receive([ref]$ep)
[System.Text.Encoding]::ASCII.GetString($response)
$udp.Close()
Arduino (ESP8266/ESP32)
#include <WiFiUdp.h>
WiFiUDP udp;
const char* server = "bbtime.bbserver.eu";
const int port = 4444;
// Trigger payload (bytes 2-64). bbId fills bytes 0-1.
const byte TRIGGER_PAYLOAD[63] = {
0x01, 0xFF,
0x00, 0x77, 0xFF, 0x45, 0x05, 0x00, 0x19, 0x37,
0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
0x23, 0x25, 0x58, 0x42, 0x16, 0x92,
0x02, 0x01, 0x00, 0x01, 0x20, 0x1F, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x72, 0x41, 0x29, 0x01, 0x10,
0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
void sendTrigger(uint16_t bbId) {
byte packet[65];
packet[0] = (bbId >> 8) & 0xFF; // BB ID high byte
packet[1] = bbId & 0xFF; // BB ID low byte
memcpy(packet + 2, TRIGGER_PAYLOAD, sizeof(TRIGGER_PAYLOAD));
udp.beginPacket(server, port);
udp.write(packet, sizeof(packet));
udp.endPacket();
int packetSize = 0;
unsigned long start = millis();
while (!packetSize && millis() - start < 2000) {
packetSize = udp.parsePacket();
}
if (packetSize) {
char buf[64];
int len = udp.read(buf, sizeof(buf) - 1);
buf[len] = '\0';
// buf contains: +CCLK: "YY/MM/DD,HH:MM:SS+ZZ"
Serial.println(buf);
}
}
MicroPython (ESP32/RP2040)
import socket
# 65-byte trigger packet from BB ID 0x2300 (bytes 0-1).
TRIGGER_HEX = (
'2300' # bytes 0-1: BB ID
'01ff' # bytes 2-3: frame_id + bb_status
'0077ff4505001937' # bytes 4-11
'123456789012' # bytes 12-17 (code)
'232558421692' # bytes 18-23
'0201000120' # bytes 24-28
'1f00ffff' # bytes 29-32
'00000000' # bytes 33-36
'7241290110' # bytes 37-41
'ffffff' # bytes 42-44
+ '00' * 20 # bytes 45-64
)
def send_trigger(server_ip, bb_id=None, port=4444):
packet = bytearray(bytes.fromhex(TRIGGER_HEX))
if bb_id is not None:
packet[0] = (bb_id >> 8) & 0xFF
packet[1] = bb_id & 0xFF
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(2)
sock.sendto(bytes(packet), (server_ip, port))
try:
data, _ = sock.recvfrom(64)
# data contains: +CCLK: "YY/MM/DD,HH:MM:SS+ZZ"
print(data.decode())
except OSError:
print("Timeout waiting for response")
finally:
sock.close()
# Example: send trigger as BB ID 0x2305
send_trigger("bbtime.bbserver.eu", 0x2305)