Przejdź do treści

Komunikacja MQTT

Dane serwera deweloperskiego

  • Adres: vemmio.dev
  • Port: 1883
  • Nazwa użytkownika: vemmio
  • Hasło użytkownika: Q4xF6KYfvGgrMDmjcaBTiYuPixTxaCox8regAAdqAmCePbkFw7CR8Dfd8nEPhRuL

Definicje protobuf

vemmiopb.zip

Informacje ogólne

Urządzenie wysyła okresowo komunikat PresenceNotification na temat presence/AA:BB:CC:DD:EE:FF.

message PresenceNotification {
  string mac = 1;
  string version = 2;
  string git_commit = 3;
  string build_time = 4;
  string firmware_version = 5;
}

Po otrzymaniu tej informacji serwer uznaje urządzenie za połączone.

Serwer sprawdza co 15 sekund czy ma aktualne informacje o urządzeniu. Jeśli ostatnia aktualizacja informacji nie wystąpiła w ciągu ostatnich 30 sekund, serwer uznaje urządzenie za rozłączone.

Raporty

Urządzenie wysyła komunikaty GatewayReport na temat reports/AA:BB:CC:DD:EE:FF.

Komunikat zawiera identyfikator urządzenia i treść raportu urządzenia.

message GatewayReport {
  string mac = 1;
  oneof report {
    ...
    DeviceReport device = 3;
  }
}

W treści raportu urządzenia przesyła dane identyfikacyjne urządzenia, chwilę czasową wystąpienia raportu oraz treść raportu odpowiednią dla typu urządzenia.

message DeviceReport {
  DeviceMetadata metadata = 1;
  google.protobuf.Timestamp timestamp = 2;
  oneof report {
    SwitchReport switch = 3;
    ...
    TemperatureReport temperature = 12;
    ...
    WiFiReport wifi = 28;
    ...
  }
}

Dane identyfikacyjne uzupełniamy w zależności od rodzaju urządzenia.

Przykładowo dla przekaźnika i czujnika temperatury WiFi wykorzystamy MQTTMetadata. W celu przesłania informacji o sile sygnału WiFi uzupełnimy WiFiMetadata.

message DeviceMetadata {
  oneof metadata {
    ...
    WiFiMetadata wifi = 4;
    ...
    MQTTMetadata mqtt = 6;
  }
}

W przypadku informacji o sieci WiFi, dane identyfikacyjne nie zawierają szczegółów.

message WiFiMetadata {}

Dane identyfikacyjne urządzenia WiFi zawierają identyfikator urządzenia zakodowany do tablicy bajtów w sposób, który znać musi tylko urządzenie.

W przypadku prostych urządzeń identyfikator urządzenia może być pusty.

Jeśli jednak urządzenie będzie zawierało powielające się funkcje (np. dwa przekaźniki) identyfikator urządzenia musi zostać uzupełniony, aby możliwa była jego identyfikacja.

message MQTTMetadata {
  bytes device_id = 1;
}

Przykładowy raport przekaźnika zawiera informację o jego stanie.

message SwitchReport {
  SwitchValue value = 1;
}

enum SwitchValue {
  SWITCH_UNKNOWN = 0;
  SWITCH_ON = 1;
  SWITCH_OFF = 2;
}

W skład raportu czujnika temperatury wchodzą wartość i odpowiadającej jej jednostka.

message TemperatureReport {
  Unit unit = 1;
  double value = 2;
}

enum Unit {
  UNKNOWN = 0;
  CELSIUS = 1;
  FAHRENHEIT = 2;
  ...
}

Sterowanie

Sterowanie realizowane jest w modelu synchronicznym — żądanie/odpowiedź.

sequenceDiagram
  actor U as Użytkownik
  participant S as Serwer
  participant B as Broker
  participant D as Urządzenie

  D->>B: subskrypcja<br/>commands/AA:BB:CC:DD:EE:FF
  U->>S: włącz przekaźnik
  S->>B: subskrypcja $response_topic$
  S->>B: publikacja żądania mqtt_req<br/>commands/AA:BB:CC:DD:EE:FF
  B->>D: przekazanie żądania mqtt_req
  D->>B: publikacja potwierdzenia ACK
  D->>D: włączenie przekaźnika
  alt włączenie zakończone sukcesem
    D->>B: publikacja odpowiedzi typu DATA
  else włączenie nie powiodło się
    D->>B: publikacja odpowiedzi typu ERROR
  end
  B->>S: przekazanie odpowiedzi

Opis kroków na przykładzie próby włączenia przekaźnika.

  • Urządzenie subskrybuje się na temacie commands/AA:BB:CC:DD:EE:FF.

  • Użytkownika zainicjował chęć włączenia przełącznika Z-Wave.

  • Serwer subskrybuje się na temacie o losowej nazwie, dalej będziemy się do niego odwoływać przez zwrot $response_topic.

  • Serwer przygotowuje paczkę danych (mqttreq) żądania włączenia przekaźnika.

metadata := &vemmiopb.DeviceMetadata{
        Metadata: &vemmiopb.DeviceMetadata_Mqtt{
                Mqtt: &vemmiopb.MQTTMetadata{},
        },
}
data := &vemmiopb.CommandRequestData{
        Data: &vemmiopb.CommandRequestData_SwitchOn{
                SwitchOn: &vemmiopb.SwitchRequest{
                        Metadata: metadata,
                },
        },
}
req := &pb.CommandRequest{
        Method: "Switch/SwitchOn",
        Type:   vemmiopb.CommandRequestType_REQUEST_TYPE_DATA,
        Data:   data,
}
mqttreq := &vemmiopb.MQTTCommandRequest{
        Request: req,
        ResponseTopic: "$response_topic",
}
  • Serwer publikuje paczkę danych (mqttreq) na temat commands/AA:BB:CC:DD:EE:FF.

  • Urządzenie odbiera paczkę danych (mqttreq).

  • Urządzenie publikuje potwierdzenie otrzymania żądania na temacie $response_topic.

ack := &vemmiopb.CommandReply{
        Type: vemmiopb.CommandReplyType_REPLY_TYPE_ACK,
}
  • Urządzenie na podstawie wartości pola Method rozpoznaje typ żądania i je obsługuje.

  • Urządzenie publikuje odpowiedź na wysłane żądanie na temacie $response_topic.

W przypadku pomyślnego wykonania żądania, serwer oczekuje na odpowiedź zawierającą rezultat wykonania żądania (dla przekaźników rezultat nie zawiera danych).

reply := &pb.CommandReply{
        Type: vemmiopb.CommandReplyType_REPLY_TYPE_DATA,
        Data: &pb.CommandReplyData{
                Data: &pb.CommandReplyData_SwitchOn{
                        SwitchOn: &pb.SwitchResponse{},
                },
        },
}

W przypadku błędu wykonania żądania, serwer oczekuje na odpowiedź zawierającą komunikat o błędzie.

reply := &vemmiopb.CommandReply{
        Type:  vemmiopb.CommandReplyType_REPLY_TYPE_ERROR,
        Error: &vemmiopb.CommandReplyError{
                Message: "...",
        },
}

Żądania niewymagające odpowiedzi

Struktura CommandRequest została rozszerzona o listę opcji, która pozwala serwerowi zakomunikować oczekiwania dotyczące odpowiedzi.

message CommandRequest {
  string method = 1;
  CommandRequestType type = 2;
  CommandRequestData data = 3;
  bytes payload = 4;
  repeated CommandRequestOption options = 5;
}

enum CommandRequestOption {
  REQUEST_OPTION_UNSPECIFIED = 0;
  REQUEST_OPTION_NOACK = 1;
  REQUEST_OPTION_NORESPONSE = 2;
}

Obsługiwane opcje i ich znaczenie:

  • REQUEST_OPTION_NOACK - serwer nie czeka na potwierdzenie otrzymania żądania
  • REQUEST_OPTION_NORESPONSE - serwer nie czeka na odpowiedź zawierającą rezultat wykonania żądania