Skip to content

Local channels

There is no BLE, mDNS, UDP or multicast in the app. The box is reached over TCP only:

  • in normal operation, on the home network, port 400: obfuscated commands;
  • during setup, on the box's own access point, 10.10.10.1:23: plain-text commands.

The rcl/ package (relays reached at 192.168.4.1:3001) belongs to other products built from the same codebase. It is disabled in the Daisy app (Utils#isDirectApp() is false) and is not covered here.

Home network: TCP port 400 (DaisyApplication#sendDM)

Finding the box. Its address comes only from the cloud: the status item NET_PARAM of the box device (status-device-list with idInstallationDevice = Installation.idInstallationDevice) holds IP: a.b.c.d NameNet: <ssid> (DaisyApplication#saveNetParam). The phone is considered "at home" when its current SSID equals NameNet. An IP of 0 means unknown.

Exchange. One TCP connection per command (connect timeout 500 ms). The client writes the frame (no newline) and reads one line:

  • the line contains ACK → success;
  • another line → the app clears the stored IP and re-sends through the cloud;
  • no line within the read timeout (5 s; 10 s for a scenario; 2 s when the first command's action is CHANNEL) → the app reports success and does not re-send (avoids executing twice);
  • connection error → the app clears the stored IP and falls back to the cloud.

The LAN only accepts commands. Device state is never read locally.

Payload (DaisyApplication#convertForDM), built by string concatenation without JSON escaping:

{"idIn":"<instCode>","idSc":<idScenario>,"isSc":<true|false>,"cL":[{"idInDe":<idInstallationDevice>,"deCo":"<deviceCode>","cmId":<commandId>,"coAc":"<commandAction>","coPa":"<commandParam>","low":"<lowlevelCommand>","coSta":0},…]}

For command models 195–201 (generic sliders), coPa is re-encoded: each §-separated value v becomes 000 if 0, 0v if < 100, else v, each followed by - (5§120§0 → 05-120-000-).

Obfuscation (DaisyApplication#encrypt):

KEY      = "d3Cr1pTam1St0CaZzOSe61nGrad0"             # 28 chars
ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789"
r   = random 0..27;  k = KEY[r:] + KEY[:r]            # rotate left by r
ts  = str(epoch_seconds)                              # 10 digits
d(i) = chr(int(ts[i:i+2]))                            # one char per pair of digits
plain = d(0) + message with d(2), d(4), d(6) inserted BEFORE message[50], [70], [90]
        (only when the message is that long) + d(8)
x   = chars(plain) XOR k[i % 28]                      # per UTF-16 code unit
frame = ("S" if scenario else "M") + ALPHABET[r] + base64(utf8(x))   # standard alphabet, padded, no wrap

The SDK's implementation (aioteleco/local/crypto.py) is checked against vectors produced by running the app's own Java method with a fixed r and timestamp (tests/test_local_crypto.py). Whether the box enforces a time window on the embedded timestamp is not yet verified.

Diagnostic. DaisyApplication#getDiagnostic sends encrypt("DIAGNOSTIC" × 10) on port 400 (firmware ≥ 1.34). The box answers a plain-text, comma-separated log of 10-character entries (0000000000 = filler, 5555555555 = rotation marker).

Setup access point: 10.10.10.1:23

During installation the box opens an open Wi-Fi network Daisy_<instCode>. The app connects to 10.10.10.1:23 (BoxWifiConfigurationActivity, SetupWifiActivity, DaisyApplication#openApSocket) and exchanges plain-text lines:

Command Purpose
TEST_SCAN list the Wi-Fi networks seen by the box (2 header lines, then one per network)
GET_INFO, PING_CMD, DIAGNOSTIC information
AP_CHANNEL_CMD 00R / 06W / 20W read / set the Wi-Fi channel
FMEMORY ADDR: %s NB: %sR\r\n memory dump

Provisioning line (BoxWifiConfigurationActivity#sendDataSocket):

SSID: <ssid> |Pass: <password> |Acco: <idAccount> |Name: <instDescription> |Code: <instCode> |Titu: <latitude> |Gitu: <longitude>

It is sent in clear text when the box first sends a banner line, and through encrypt() when no line arrives within 2 s (newer boards). The box then registers itself with the cloud for that account, so adding a box needs no REST call. Not implemented by the SDK.