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.

Host: bbtime.bbserver.eu IPv4: 195.140.252.32 IPv6: 2A01:430:D:0:2CC:E6FF:FEF7:AE65 UDP + TCP port: 4444

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)