πŸ›°οΈZafer SatΔ±lmış - Aviora

AppProtocolZD β€” JSON protocol

Every message includes a common device header. The function field selects the operation. On the push channel, device β†’ server; on the pull channel, server β†’ device requests and (in most cases) immediate replies.

ProtocolZD state machine

Registration, alive, and pull handling
stateDiagram-v2
  [*] --> Init: appProtocolZDStart
  Init --> Registering: connect push, send ident
  Registering --> Registered: response.register true
  Registering --> Registering: 30s timeout, retry
  Registered --> Registered: alive every 5 min
  Registered --> Registered: handle pull messages
  Registered --> Registered: push data when meter job completes

Common header (all messages)

{
  "device": {
    "flag": "AVI",
    "serialNumber": "0123456789ABCDE"
  },
  ...
}

flag is a product constant; serialNumber is the serial programmed into the device.

1. Ident (registration) β€” Push

Device β†’ server

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "ident",
  "response": {
    "registered": false,
    "brand": "AVI",
    "model": "AVIO2622",
    "deviceDate": "2021-06-02 17:19:58",
    "pullIP": "192.168.1.10",
    "pullPort": 2622
  }
}

registered: false means first-time registration; if persisted, true is sent. If the server does not answer, retry after ~30 s.

Server β†’ device (same push socket)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "ident",
  "response": { "register": true }
}

register: true means acceptance; device state is saved to file so ident is not required again after reboot.

2. Alive β€” Push

Device β†’ server (e.g. every 5 minutes)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "alive",
  "response": { "deviceDate": "2021-06-02 17:19:58" }
}

Server β†’ device (optional)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "ack"
}

On error, "function": "nack". The device resends on the next period even if no reply is received.

3. Log β€” Pull

Server β†’ device

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "log"
}

Device β†’ server (same pull session, may be packetized)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "log",
  "packetNum": 1,
  "packetStream": true,
  "response": { "log": "... up to ~1024-byte JSON body ..." }
}

Last packet has packetStream: false. If there is no log, log: "NO-LOG".

4. Setting β€” Pull

Server β†’ device (server IP/port + meter add/remove)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "setting",
  "request": {
    "Server": { "ip": "192.168.1.100", "port": 8722 },
    "meters": [
      {
        "operation": "add",
        "meter": {
          "protocol": "IEC62056",
          "type": "electricity",
          "brand": "MKL",
          "serialNumber": "12345678",
          "serialPort": "port-1",
          "initBaud": 300,
          "fixBaud": false,
          "frame": "7E1"
        }
      },
      {
        "operation": "remove",
        "meter": { "brand": "MKL", "serialNumber": "12345678" }
      }
    ]
  }
}

Device β†’ server

{ "device": {...}, "function": "ack" }

On failure, nack. If the server address is updated, the TCP manager is restarted.

5. fwUpdate β€” Pull

Server β†’ device

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "fwUpdate",
  "request": { "address": "ftp://user:pass@host:21/path/file.bin" }
}

Device β†’ server

{ "device": {...}, "function": "ack" }

Then the FTP download task is started (AppSwUpdateInit).

6. Readout β€” Pull + push

a) Server β†’ device (pull)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "readout",
  "request": {
    "directive": "ReadoutDirective1",
    "parameters": { "meterSerialNumber": "12345678" }
  }
}

b) Device β†’ server (pull, if JSON is valid)

{ "device": {...}, "function": "ack" }

Invalid request β†’ nack. Job is queued.

c) When done, device β†’ server (push, packetized)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "readout",
  "packetNum": 1,
  "packetStream": false,
  "response": {
    "data": {
      "id": "/LGZ5\\2ZMG405000b.P07",
      "readout": "0.0.0(23660088)..."
    }
  }
}

d) Server β†’ device (push)

{ "device": {...}, "function": "ack" }

Even if the server never answers, _meterID.txt and _readout.txt are deleted.

7. Load profile β€” Pull + push

Server β†’ device (pull)

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "loadprofile",
  "request": {
    "directive": "ProfileDirective1",
    "METERSERIALNUMBER": "12345678",
    "startDate": "2021-06-22 00:00:00",
    "endDate": "2021-06-22 12:05:00"
  }
}

ACK/NACK same idea as readout. Payload is read from _payload.txt; the id field uses load-profile-no-id; content is still packed under the readout key in the implementation.

8. directiveList β€” Pull

Server β†’ device

{
  "device": { "flag": "AVI", "serialNumber": "0123456789ABCDE" },
  "function": "directiveList",
  "request": { "filter": { "id": "ReadoutDirective" } }
}

id: "*" returns all directives; each in a separate message with packetNum / packetStream.

9. directiveAdd / directiveDelete β€” Pull

Add request

{
  "function": "directiveAdd",
  "device": {...},
  "request": {
    "directive": {
      "id": "DirectiveID",
      "directive": [
        { "operation": "setBaud", "parameter": "300" },
        { "operation": "setFraming", "parameter": "7E1" }
      ]
    }
  }
}

Delete

{
  "function": "directiveDelete",
  "device": {...},
  "request": { "filter": { "id": "DirectiveID" } }
}

Reply: ack or nack. For delete, id: "*" removes all.

End-to-end readout sequence (Mermaid)

Pull request β†’ push data
sequenceDiagram
  participant S as Server
  participant Pull as Device pull :2622
  participant PZ as ProtocolZD
  participant MO as MeterOps
  participant Push as Device push to server
  S->>Pull: readout + request JSON
  Pull->>PZ: incoming message
  PZ->>S: ack (pull)
  PZ->>MO: AddReadoutTask
  MO-->>PZ: callback SUCCESS
  PZ->>Push: readout packets
  S->>Push: ack
  PZ->>PZ: delete output files