Albicchiere

Albi device shadows

Documentation for Albi Shadow Communications

1. Definizione topic e shadow

La creazione delle shadow avviene in modo contestuale alla creazione della thing associata al dispositivo. Le shadow sono le seguenti:

  • Device shadow (device)
  • Config shadow (config)
  • Smart Bag shadow (bag)

1.1. Device Shadow

La device shadow contiene tutti i dati del dispositivo di cui l'applicazione necessita e le impostazioni modificabili dall'utente.

MQTT TOPIC PREFIX: $aws/things/<thingname>/shadow/name/device

{
    "state": {
        "desired": {           
            "ownerId": "63652c2d4d1ead907898911d",
            "name": "Albi Home",
            "chassis": { //presente solo per modelli Albi Pro, altrimenti vuoto
                "chassisId": "63156c2d4d1ead907898911d",
                "slot": 3
            },
            "serviceSchedule": "2023-01-01T00:00:00.000Z",
            "coolingMode": "eco", // | "boost" | "silent"
            "parentalControl": false, // | true
            "locale": "it",
            "displayTimeout": 30000 //tempo in ms
        },
        "reported": {
            "ownerId": "63652c2d4d1ead907898911d",
            "serial": "AH11223141213",
            "name": "Albi Home",
            "wifiName": "AlbiFi",
            "chassis": {
                "chassisId": "63156c2d4d1ead907898911d",
                "slot": 3
            }, 
            "macAddress": "00-50-FC-A0-67-2C",
            "firmware": "1.10.1",
            "serviceSchedule": "2023-01-01T00:00:00.013Z",
            "wineReadyAt": "2024-01-01T00:00:00.013Z",
            "coolingMode": "eco",
            "parentalControl": false,
            "locale": "it",
            "displayTimeout": 300000,
            "batteryStatus": "empty", // "low" | "half" | "full" | "empty-charging" | "low-charging" | "half-charging" | "full-charging"
            "alerts":["E01","E02"]
        }
    }
}

Default:

{
    "state": {
        "desired": {           
            "coolingMode": "eco", // | "boost" | "silent"
            "parentalControl": false, // | true
            "displayTimeout": 300000 //tempo in ms
        },
        "reported": null
        }
}

1.2. Config Shadow

La config shadow contiene tutti i parametri di configurazione del dispositivo che permettono ad Albicchiere di modificarne il comportamento.

MQTT TOPIC PREFIX: $aws/things/<thingname>/shadow/name/config

{
    "state": {
        "desired": {
            "hasBattery": false, //indica se la variante del dispenser ha batteria o meno
            "offsetTambient": 0.0, //offset in gradi °C da sommare a 't_ambient'
            "offsetTheatsink": 0.0, //offset in gradi °C da sommare a 't_heatsink'
            "offsetTinternal": 0.0, //offset in gradi °C da sommare a 't_internal'
            "offsetTwine": 0.0, //offset in gradi °C da sommare a 't_wine'
            "delayOpening": 0, //offset in ms per l'apertura del carrello
            "delayClosing": 0, //offset in ms per la chiusura del carrello
            "pressureOffset": 0, //offset in mbar per la misura della pressione
            "deviceLocked": false, //indica se il dispenser può erogare da smart bag con seriale non presente a DB
            "samplingMetrics": 300000, //tempo in ms, indica ogni quanto mandare dati su topic metrics
            "thresholds": {
                "tAmbient":[0.0,40.0], //°C
                "tWine":[0.0,30.0], //°C
                "tHeatsink":80.0, //°C
                "inflateTime":30000 //millisecondi 
            } //soglie per warning sensori 
        },
        "reported": {
            "hasBattery": false,
            "offsetTambient": 0.0,
            "offsetTheatsink": 0.0,
            "offsetTinternal": 0.0,
            "offsetTwine": 0.0,
            "delayOpening": 0,
            "delayClosing": 0,
            "pressureOffset": 0,
            "deviceLocked": false,
            "samplingMetrics": 300000,
            "thresholds": {
                "tAmbient":[0.0,40.0],
                "tWine":[0.0,30.0],
                "tHeatsink":80.0,
                "inflateTime":30000
            }
        }
    }
}

Default:

{
    "state": {
        "desired": {
            "hasBattery": false,
            "offsetTambient": 0.0,
            "offsetTheatsink": 0.0,
            "offsetTinternal": 0.0,
            "offsetTwine": 0.0,
            "delayOpening": 400,
            "delayClosing": 400,
            "pressureOffset": 0,
            "deviceLocked": false,
            "samplingMetrics": 300000,
            "thresholds": {
                "tAmbient":[0.0,40.0],
                "tWine":[0.0,30.0],
                "tHeatsink":80.0, 
                "inflateTime":30000
            } 
        },
        "reported": null
    }
}

1.3. Smart Bag Shadow

Contiene i dati della bag inserita all'interno del dispenser.

MQTT TOPIC PREFIX: $aws/things/<thingname>/shadow/name/bag

{
    "state": {
        "desired": {
            "bagSerial": "E00208007F8A1D8C",
            "smartBag": {
                "_id": "63652c2d4d1ead907898911d",
                "model": "SB13450",
                "customTemperature": 4, // potrebbe essere non presente, se presente sovrascrive `temperature`
                "type": "empty", // | "bottled"
                "quantityLeft": 750, // dividendo per 125 si ottiene il numero dei bicchieri
                "qualityScore": 100,
                "bestBefore": "2000-01-01T00:00:00.013Z",
                "expiryDate": "2000-01-01T00:00:00.013Z",
                "refillCounter": 0
            },
            "vintage": {
                "_id": "63652c2d4d1ead907898911d",
                "wineId": "63652c2d4d1ead907898911d",
                "name": "Maria Camilla",
                "winery": "Castello Monte Vibiano Vecchio",
                "wineColor": "white", // | "rose" | "red"
                "region": "Umbria",
                "grapes": [
                    "Grechetto",
                    "Sangiovese"
                ],
                "year": "2018", // è una stringa, potrebbe essere "N.V." (non-vintage)
                "alcohol": 14.5,
                "temperature": 15, // numero intero
                "label": false, // | true
                "labelQuality": "low", // | "medium" | "high"
                "parentalControl": false // | true
            },
            "userVintage": {}
        },
        "reported": {
            "bagSerial": "E00208007F8A1D8C",
            "smartBag": {
                "_id": "63652c2d4d1ead907898911d",
                "model": "SB13450",
                "customTemperature": 4,
                "type": "empty",
                "quantityLeft": 750,
                "qualityScore": 100,
                "bestBefore": "2000-01-01T00:00:00.013Z",
                "expiryDate": "2000-01-01T00:00:00.013Z",
                "refillCounter": 0
            },
            "vintage": {
                "_id": "63652c2d4d1ead907898911d",
                "wineId": "63652c2d4d1ead907898911d",
                "name": "Maria Camilla",
                "winery": "Castello Monte Vibiano Vecchio",
                "wineColor": "white",
                "region": "Umbria",
                "grapes": [
                    "Grechetto",
                    "Sangiovese"
                ],
                "year": "2018",
                "alcohol": 14.5,
                "temperature": 15,
                "label": false,
                "labelQuality": "low",
                "parentalControl": false
            },
            "userVintage": {}
        }
    }
}

Oppure:

{
    "state": {
        "desired": {
            "bagSerial": "E00208007F8A1D8C",
            "smartBag": {
                "_id": "63652c2d4d1ead907898911d",
                "model": "SB13450",
                "customTemperature": 4, // potrebbe essere non presente, se presente sovrascrive `temperature`
                "type": "empty", // | "bottled"
                "quantityLeft": 750, // dividendo per 125 si ottiene il numero dei bicchieri
                "qualityScore": 100,
                "bestBefore": "2000-01-01T00:00:00.013Z",
                "expiryDate": "2000-01-01T00:00:00.013Z",
                "refillCounter": 0
            },
            "vintage": {},
            "userVintage": {
                "_id": "63652c2d4d1ead907898911d",
                "name": "Maria Camilla",
                "winery": "Castello Monte Vibiano Vecchio",
                "wineColor": "white", // | "rose" | "red"
                "region": "Umbria",
                "grapes": [
                    "Grechetto",
                    "Sangiovese"
                ],
                "year": "2018",
                "alcohol": 14.5,
                "temperature": 15,
                "label": false, // | true
                "parentalControl": false // | true
            }
        },
        "reported": {
            "bagSerial": "E00208007F8A1D8C",
            "smartBag": {
                "_id": "63652c2d4d1ead907898911d",
                "model": "SB13450",
                "customTemperature": 4,
                "type": "empty",
                "quantityLeft": 750,
                "qualityScore": 100,
                "bestBefore": "2000-01-01T00:00:00.013Z",
                "expiryDate": "2000-01-01T00:00:00.013Z",
                "refillCounter": 0
            },
            "vintage": {},
            "userVintage": {
                "_id": "63652c2d4d1ead907898911d",
                "name": "Maria Camilla",
                "winery": "Castello Monte Vibiano Vecchio",
                "wineColor": "white",
                "region": "Umbria",
                "grapes": [
                    "Grechetto",
                    "Sangiovese"
                ],
                "year": "2018",
                "alcohol": 14.5,
                "temperature": 15,
                "label": false,
                "parentalControl": false
            }
        }
    }
}

Default:

{
    "state": {
        "desired": null,
        "reported": null           
    }
}

1.4. Metrics Topic

Manda le grandezze che identificano lo stato del dispositivo periodicamente (intervallo definito nella Config Shadow).

MQTT TOPIC: /dispenser/<thingname>/metrics

  {
    "t_internal": "5.0", // °C
    "t_wine": "12.1", // °C
    "t_keyboard": "25.6", // °C
    "t_heatsink": "35.8", // °C
    "pressure": "0", // mbar
    "plt_pwm": "100", // %
    "fan_pwm": "100", // %
    "fan_tacho": "200", // rpm
    "fan_life": "32800", // hours
    "plt_life": "35000", // hours
    "battery_life": "150", // hours
    "motor_life": "150", // number of cycles
    "display_life": "15000", // hours
    "life": "45000" // hours
  }

1.5. Logs (Errori, log e warning) Topic

Manda warning ed errori o log significativi.

MQTT TOPIC: /dispenser/<thingname>/logs

{
  "timestamp": "2023-01-01T00:00:00.013Z",
  "result": {
    "code": "E12",
    "params":{} // see table below
  }
}
CodeDescriptionParamsParams DescriptionScreen
W01Serving temperature out of rangetemperatureServing temperatureX12
W02Battery level below 20%levelBattery levelX13
W03No bag inside------X14
W04No socket connection------X16
W05Vacuum errorbagSerialBag serialX9.4
E01Ambient temperature out of rangetemperatureAmbient temperatureX15
E02Cooling system error------X21
E03Serving errorbagSerialBag serialX18
E04Sensor error------X19
E05Wine temperature out of rangetemperatureWine temperatureX20
E06Heatsink temperature out of rangetemperatureHeatsink temperatureX21
E07No battery detected---------
L01PouringbagSerial, temperature1, temperature2, quantityBag serial, Serving temperature, Ambient Temperature, Taste or Drink---
L02Wine readybagSerial, temperature, quantityBag serial, Wine temperature, Quantity left---
L03Factory reset------X0.4
L04Parental control (device)------X10.1
L05Parental control (smartBag)bagSerial---X10.2

2. Definizione azioni

Azioni inviate dall'app Albicchiere (app-->backend-->dispenser)

Sez.ActionTOPIC GETTOPIC UPDATE
2.1activateDispenseractionaction_ack
2.2setCoolingModedevice shadowdevice shadow
2.3toggleParentalControldevice shadowdevice shadow
2.4factoryResetdevice shadowdevice shadow
2.5setScheduledevice shadowdevice shadow
2.6pourWineactionaction_ack
2.7startVacuumBagactionaction_ack
2.8setServingTemperaturebag shadowbag shadow

Azioni dispenser (dispenser-->backend)

Sez.AzioneTOPIC GETTOPIC UPDATE
2.9bagNFCReadbag shadowbag shadow
2.10factoryResetdevice shadowdevice shadow
2.11wineReadydevice shadowdevice shadow
2.12vintageLabelgetImageLabelaction_ack

2.1. Activate Dispenser

Durante il processo di pairing, dopo la connessione ad internet il Dispenser rimane in ascolto sul topic in attesa dell'avvenuta associazione.

MQTT TOPIC: /dispenser/<thingname>/action

{
"jobId": "63652c2d4d1ead907898911d",
"deadline": "2025-01-01T00:00:00.000Z",
"action": "activateDispenser",
"params": {
    "name": "Albi Home",
    "roomId": "43156c2d4d1ead907898911d", //non salvare
    "chassis": { //presente solo per modelli Albi Pro, altrimenti non presente
        "chassisId": "63156c2d4d1ead907898911d",
        "slot": 3
    },
    "ownerId": "63652c2d4d1ead907898911d",
    "macAddress": "00:50:FC:A0:67:2C",
    "locale": "it"
    }
}

Il Dispenser invia conferma di completamento del job al topic /dispenser/<thingname>/action_ack

{
"jobId": "63652c2d4d1ead907898911d",
"status": "completed",
"action": "activateDispenser",
"result": null
}

2.2. Cooling mode

Backend aggiorna lo stato del nuovo coolingMode aggiornando la device shadow.

MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

{
    "state": {
        "desired": {
            "coolingMode": "eco" // "boost" | "silent"
        },
        "reported": {}
    }
}

2.3. Parental Control

Backend aggiorna lo stato del nuovo parentalControl aggiornando la device shadow.

MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

{
    "state": {
        "desired": {
            "parentalControl": true // false
        },
        "reported": {}
    }
}

2.4. Factory Reset

  1. Backend cancella il campo ownerId aggiornando la device shadow.

    MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

    {
      "state": {
            "desired": {
                "ownerId": ""
            },
            "reported": {}
        }
    }
  2. Dispenser aggiorna stato reported, resetta la configurazionee va in pairing mode.

2.5. Schedule

Backend aggiorna il timestamp di raggiungimento della temperatura di servizio.

MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

{
    "state": {
        "desired": {
            "serviceSchedule": "2024-01-01T00:00:00.013Z"
        },
        "reported": {}
    }
}

Al momento specificato nel Timestamp, il dispenser reimposta il serviceSchedule al valore iniziale: "" e imposta wineReadyAt a tale data:

MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

{
    "state": {
        "desired": {
            "serviceSchedule": "",
        },
        "reported": {
            "serviceSchedule": "",
            "wineReadyAt": "2024-01-01T00:00:00.013Z"
        }
    }
}

2.5.1. Remove Schedule

Backend reimposta il timestamp al valore iniziale: "".

MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

{
    "state": {
        "desired": {
            "serviceSchedule": ""
        },
        "reported": {}
    }
}

2.6. Pour Wine

Backend invia job al dispenser per servire un bicchiere di vino in quantità taste o drink (vedi esempi di seguito)

MQTT TOPIC: /dispenser/<thingname>/action

  1. Dispenser esegue il flusso di erogazione vino.

  2. Dispenser aggiorna il numero di bicchieri rimasti nella Smart Bag shadow (drink=125ml, taste=62.5ml).

    {
        "state": {
            "desired": {
                "smartBag": {
                    "quantityLeft":625
                },
            },
            "reported": {
                "bagSerial": "E00208007F8A1D8C",
                "smartBag": {
                    "quantityLeft":625
                },
                "vintage": {},
                "wine": {}
            }
        }
    }
  3. Dispenser invia conferma di completamento del job.

    MQTT TOPIC: /dispenser/<thingname>/action_ack

    {
        "jobId": "63652c2d4d1ead907898911d",
        "status": "completed",
        "action": "pourWine",
        "result": null
    }
  4. Dispenser invia log con dati di erogazione.

    MQTT TOPIC: /dispenser/<thingname>/logs

    {
      "timestamp": "2023-01-01T00:00:00.013Z",
      "result": {
        "code": "L01",
        "params":{
            "bagSerial": "E00208007F8A1D8C",
            "temperature1": 16.0,
            "temperature2": 24.0,
            "quantity": "taste" // | "drink"
        }
      }
    }

2.6.1. Esempio Pour Drink

{
  "jobId": "63652c2d4d1ead907898911d",
  "deadline": "2024-01-01T00:00:00.013Z",
  "action": "pourWine",
  "params": {
    "quantity": "drink"
  }
}

2.6.2. Esempio Pour Taste

{
  "jobId": "63652c2d4d1ead907898911d",
  "deadline": "2024-01-01T00:00:00.013Z",
  "action": "pourWine",
  "params": {
    "quantity": "taste"
  }
}

2.7. Vacuum bag

  1. Backend invia job per la funzione vacuum bag.

    MQTT TOPIC: /dispenser/<thingname>/action

    {
        "jobId": "63652c2d4d1ead907898911d",
        "deadline": "2024-01-01T00:00:00.013Z",
        "action": "startVacuumBag",
        "params": {
            "bagSerial": "E00208007F8A1D8C",
            "bestBefore": "2024-01-01T00:00:00.013Z"
        }
    }
  2. Dispenser invia conferma di completamento del job.

    MQTT TOPIC: /dispenser/<thingname>/action_ack

    {
        "jobId": "63652c2d4d1ead907898911d",
         "status": "completed",
         "action": "startVacuumBag",
         "result": null
    }

2.8. Temperatura di servizio

  1. Backend aggiorna lo stato del nuovo customTemperature aggiornando la bag shadow.

    MQTT TOPIC: $aws/things/<thingname>/shadow/name/bag/update

    {
        "state": {
            "desired": {
                "smartBag": {
                    "customTemperature": 7 
                },
            },
            "reported": {}
        }
    }
  2. Dispenser effettua un nuovo calcolo del tempo necessario dalle tabelle usando come dati quelli usati precedentemente (Twine, Tambient e coolingMode):

    • se il nuovo t* è maggiore di quello precedente, allunga il tempo necessario e aggiorna il tempo a cui il vino sarà pronto;
    • se il nuovo t* è minore di quello precedente ma maggiore di quello trascorso, accorcia il tempo necessario e aggiorna il tempo a cui il vino sarà pronto;
    • in TUTTI gli altri casi la modifica avrà effetto dal raffreddamento successivo.

    MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

    {
        "state": {
            "desired": {},
            "reported": {
                "wineReadyAt": "2023-01-01T00:00:00.000Z", 
                },
            }
        }

2.9. Lettura info Smart Bag

  1. **Dispenser**comunica al backend il seriale della nuova smart bag inserita e resetta i valori della shadow.

    MQTT TOPIC: $aws/things/<thingname>/shadow/name/bag/update

    {
        "state": {
            "desired": {
                "bagSerial": "E00208007F8A1D8C",
                "smartBag": null,
                "vintage": null,
                "userVintage": null
            }
        }
    }
  2. Backend risponde con i dati della smart bag da salvare in memoria del dispenser.

    {
        "state": {
            "desired": {
                "bagSerial": "E00208007F8A1D8C",
                "smartBag": {...smartBag},
                "vintage": {...vintage},
                "uservintage": null
            }
        }
    }

    Oppure:

    {
        "state": {
            "desired": {
                "bagSerial": "E00208007F8A1D8C",
                "smartBag": {...smartBag},
                "vintage": null,
                "userVintage": {...userVintage}
            }
        }
    }
  3. Dispenser aggiorna la shadow con i dati aggiornati.

    MQTT TOPIC: $aws/things/<thingname>/shadow/name/bag/update

    {
        "state": {
            "reported": {
                "bagSerial": "E00208007F8A1D8C",
                "smartBag": {...smartBag},
                "vintage": {...vintage},
                "uservintage": null
            }
        }
    }

    Oppure:

    {
        "state": {
            "reported": {
                "bagSerial": "E00208007F8A1D8C",
                "smartBag": {...smartBag},
                "vintage": null,
                "userVintage": {...userVintage}
            }
        }
    }

2.10. Factory Reset

  1. Dispenser cancella il campo ownerId aggiornando la device shadow.

    MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

    {
      "state": {
            "desired": {
                "ownerId": ""
            },
            "reported": {
                "ownerId": ""
            }
        }
    }
  2. Dispenser resetta la configurazione e va in pairing mode.

2.11. Vino pronto

Dispenser comunica la data alla quale il vino sarà pronto aggiornando la device shadow.

MQTT TOPIC: $aws/things/<thingname>/shadow/name/device/update

{
    "state": {
        "reported": {           
            "wineReadyAt": "2023-01-01T00:00:00.013Z"
        },
    }
}

2.12. Immagine Etichetta

L’immagine ha risoluzione 272x480 nel formato jpeg.

  1. Dispenser effettua una prima publish sul topic con il seguente payload:

    MQTT TOPIC: /dispenser/<thingname>/getimagelabel

    {
      "bagSerial": "E00208007F8A1D8C",
      "startByte": 0,
      "lengthBuffer": 0
    }
  2. Backend restituisce la lunghezza totale del buffer con il seguente payload:

    MQTT TOPIC: /dispenser/<thingname>/imagelabelbuffer

    {
      "bagSerial": "E00208007F8A1D8C",
      "imageLength": 133300
    }
  3. Dispenser calcola il numero di pacchetti necessari e chiede il primo chunk con il seguente payload:

    MQTT TOPIC: /dispenser/<thingname>/getimagelabel

    {
      "bagSerial": "E00208007F8A1D8C",
      "startByte": 0,
      "lengthBuffer": 8000
    }
  4. Backend restituisce la porzione di byte richiesti a partire da startByte per la lunghezza di lengthBuffer con il seguente payload:

    MQTT TOPIC: /dispenser/<thingname>/imagelabelbuffer

    {
      "bagSerial": "E00208007F8A1D8C",
      "startByte": 0,
      "lengthBuffer": 8000,
      "buffer": <rawbyte>
    }

    rawbyte sono i byte dell’immagine nell’intervallo startByte e lengthBuffer in formato base64

  5. Dispenser continua ad effettuare chiamate sul topic incrementando il campo startByte in modo da scaricare tutti i pacchetti successivi.

    MQTT TOPIC: /dispenser/<thingname>/getimagelabel

  6. Dispenser visualizza l'etichetta scaricata.