Sottoscrizioni di oggetti
Le sottoscrizioni sono servizi che ricevono e rispondono agli eventi. Una sottoscrizione è associata a un'origine, in genere un oggetto. Un oggetto può disporre di una sottoscrizione a un evento che risponde con un'azione. Se un'entità attiva un evento Surriscaldamento del motore, ad esempio, può effettuare la sottoscrizione a tale evento attivando una sottoscrizione Spegnere il motore. Gli oggetti possono ereditare sottoscrizioni dai modelli di oggetto e dalle thing shape che utilizzano.
Una sottoscrizione è simile a un servizio standard, ma è collegata in modo esplicito a uno o più eventi. Ciò consente di disaccoppiare l'evento dal codice che risponde all'evento stesso. Come per un servizio, è possibile implementare la logica aziendale personalizzata per reagire all'evento. È possibile sfruttare le funzionalità del modello inviando messaggi e-mail tramite un oggetto server di posta, scrivendo in un database o chiamando qualsiasi servizio disponibile nella piattaforma. A differenza del servizio, una sottoscrizione non ha un output di reso esplicito. Può, tuttavia, chiamare qualsiasi altro servizio nel modello a cui il contesto di protezione del thread ha accesso. Il contesto di protezione del thread di una sottoscrizione viene impostato in modo che coincida con il contesto di protezione del thread dell'evento che è stato attivato. Per implementare i servizi è possibile utilizzare lo stesso ambiente di modifica JavaScript.
Le sottoscrizioni prevedono un input definito costituito dal pacchetto di dati generato dall'evento, definito "dati dell'evento". Se l'entità effettua la sottoscrizione a un evento definito, i dati dell'evento vengono trasmessi alla funzione della sottoscrizione. I dati dell'evento sono descritti dalla data shape dell'evento. Nell'implementazione della sottoscrizione i dati passati dall'evento fungono da input per la funzione di script. Ad esempio, se un'entità è sottoscritta a un evento di modifica dei dati delle proprietà di un oggetto, viene chiamata la funzione di script di sottoscrizione. Di conseguenza, il valore della proprietà dell'oggetto, insieme ad altri dati rilevanti dell'evento, viene trasmesso alla funzione come parte dei dati dell'evento.
Più entità possono effettuare la sottoscrizione allo stesso evento. Ogni entità riceve una chiamata alla sottoscrizione con i dati dell'evento trasmessi. Un'entità può eseguire qualsiasi azione dello script della sottoscrizione per soddisfare i requisiti della soluzione.
Di seguito sono elencati alcuni vantaggi dell'utilizzo di questa tecnica rispetto all'utilizzo di un servizio chiamato da un altro servizio.
Un evento può essere sottoscritto da una o più sottoscrizioni.
Gli eventi vengono richiamati in base all'attività del sistema e non è necessaria alcuna interazione dell'utente.
Se a un evento sono sottoscritti più oggetti, è possibile utilizzare una sottoscrizione anziché concatenare più servizi.
È possibile effettuare la sottoscrizione a più di un evento e da entità diverse.
* 
Trigger evento e sottoscrizioni vengono eseguiti in modo asincrono. Ad esempio, una richiesta API di aggiornamento della proprietà riceve una risposta immediata al termine dell'azione di aggiornamento della proprietà. Non attende la risposta delle sottoscrizioni successive all'evento modifica dati per il completamento.
Sottoscrizioni multiple
Le sottoscrizioni hanno un nome definito dall'utente come identificatore univoco. Le entità possono disporre di più sottoscrizioni a un evento in un oggetto. Se un'entità attiva un evento Surriscaldamento del motore, ad esempio, può effettuare all'evento sia una sottoscrizione Spegnere il motore che una sottoscrizione Creare un ordine di lavorazione affinché il servizio di manutenzione controlli il motore. Per l'evento può inoltre essere creato un numero illimitato di altre sottoscrizioni.
Se un modello di oggetto o una thing shape implementa una sottoscrizione a un evento, anche gli oggetti che utilizzano il modello di oggetto o la thing shape possono creare sottoscrizioni allo stesso evento e non è necessario trovare soluzioni alternative per eseguire azioni aggiuntive quando tali eventi vengono attivati.
Sottoscrizioni distribuite
Le sottoscrizioni distribuite consentono di distribuire le esecuzioni delle sottoscrizioni in tutti i nodi ThingWorx quando un evento attiva un numero elevato di istanze di sottoscrizioni. Ad esempio quando molti oggetti effettuano la sottoscrizione allo stesso evento timer o scheduler. Ciò consente la scalabilità orizzontale dell'esecuzione della sottoscrizione basata su timer/scheduler in tutti i nodi ThingWorx in ambienti a disponibilità elevata per un utilizzo più efficiente delle risorse e prestazioni migliori. Per impostare questo comportamento, si utilizza la casella di controllo Distribuita nella scheda Info sottoscrizione. Se la casella di controllo Distribuita è deselezionata, le sottoscrizioni a timer e scheduler vengono eseguite nello stesso nodo in cui viene generato l'evento timer o scheduler. Per ulteriori informazioni sulla configurazione correlata, vedere quanto segue:
Per informazioni sulla configurazione in un ambiente locale, vedere Configurazione di SSL/TLS per Akka.
Sottoscrizioni a più eventi
La funzionalità di sottoscrizione a più eventi consente ai clienti di effettuare la sottoscrizione a più eventi, anche da oggetti diversi, per una singola sottoscrizione. Questa operazione risulta necessaria soprattutto per le sottoscrizioni complesse. Ad esempio, i clienti possono creare sottoscrizioni che potrebbero essere attivate da più modifiche di proprietà diverse ed eseguire una semplice regola if-then-else su tali valori di proprietà per eseguire azioni in base ai risultati. Per un esempio, vedere Caso di utilizzo 2. In alternativa, creare una sottoscrizione in base all'evento del timer per impostare la regola della finestra temporale. Per un esempio, vedere Caso di utilizzo 3.
* 
La funzionalità di sottoscrizione a più eventi è visibile solo durante la creazione di una nuova sottoscrizione. La sottoscrizione legacy, creata con ThingWorx 9.4 e versioni successive, rimarrà la stessa e non sarà possibile effettuarla a più di un evento.
Con la possibilità di utilizzare le sottoscrizioni a più eventi, si introduce il concetto di inserimento batch, che prevede la consegna a una sottoscrizione di più eventi alla volta, raggruppati in base alla data e all'ora delle proprietà aggiornate. Per ulteriori informazioni, vedere Proprietà degli oggetti. Per ulteriori informazioni sull'oggetto remoto, vedere Servizi degli oggetti remoti.
* 
Se si utilizzano le API delle estensioni Java getSubscriptions o getInstanceSubscriptions, è necessario utilizzare invece l'opzione getMultiEventSubscriptions oppure getInstanceMultiEventSubscriptions. getSubscriptions e getInstanceSubscriptions non supportano i formati di sottoscrizione ThingWorx 9.5 e versioni successive. Questo è valido solo se si dispone di un'entità contenente una combinazione di sottoscrizioni create prima e dopo ThingWorx 9.5. Le nuove API supportano il formato di sottoscrizione legacy (precedente a ThingWorx 9.5) e il nuovo formato di sottoscrizione (ThingWorx 9.5 e versioni successive).
Per impostare questo comportamento, si utilizza il segno + accanto all'elenco a discesa Eventi nella scheda Input della sottoscrizione. È possibile gestire l'elenco degli eventi della sottoscrizione. Ad esempio, aggiungere o eliminare eventi e modificare le informazioni sull'evento. A ogni evento aggiunto viene assegnato un alias definito dall'utente come identificatore univoco. Questo alias deve essere utilizzato per accedere a eventData tramite JavaScript. Per ulteriori informazioni sull'accesso a eventData, vedere le informazioni riportate di seguito.
* 
Quando si aggiornano più proprietà per la stessa data e ora, è preferibile utilizzare i nuovi servizi UpdatePropertyValuesBatched e UpdateSubscribedPropertyValuesBatched anziché i servizi legacy UpdatePropertyValues e UpdateSubscribedPropertyValues. Con i nuovi servizi, le sottoscrizioni a più eventi vengono eseguite esattamente una volta per data e ora e nella stessa esecuzione si ottengono i nuovi valori per tutte le proprietà modificate. In questo modo si riduce il numero complessivo di esecuzioni delle sottoscrizioni rispetto ai servizi legacy e questo si traduce in un minore consumo di CPU.
Accesso a eventData
L'accesso alle informazioni di eventData tramite JavaScript viene eseguito con l'alias dell'evento. Uno sviluppatore non può più accedere a eventData mediante event.eventData.newValue, ma deve utilizzare il nome univoco dell'alias e del livello events[] per accedere a un evento eventData specifico, ad esempio events["AliasName"].eventData.newValue.value.
* 
Questa linea guida è valida solo per le nuove sottoscrizioni create a partire da ThingWorx 9.5 e versioni successive. Le sottoscrizioni create prima della versione 9.5 possono ancora accedere a eventData tramite event.eventData.newValue.
È possibile che solo una parte degli eventi associati attivi la sottoscrizione. Accedere a uno degli eventi eventData che non hanno attivato la sottoscrizione può causare un errore, pertanto è necessario prima controllare se l'accesso a eventData è definito. Ad esempio:
try {
if (events["Me_DataChange_p1"].eventData.newValue.value ==44 {

} catch (error) {
logger.error(" p1 event is not defined " + error);
}
Di seguito viene riportato un altro esempio.
if( events["Me_DataChange_p1"] !== undefined ){
if(events["Me_DataChange_p1"].eventData.newValue.value)==44;{

}
}
Sottoscrizioni ordinate e con stato
Una sottoscrizione ordinata è destinata ai casi di utilizzo che richiedono ordinamento e atomicità. È visibile solo quando si crea una nuova sottoscrizione. Le sottoscrizioni create con ThingWorx 9.4 e versioni precedenti rimangono inalterate e non possono essere eseguite in sequenza.
Senza questa funzionalità, le sottoscrizioni vengono eseguite in modo asincrono, in parallelo, e non possono essere con stato (non possono includere valori tra le esecuzioni). In alcuni casi di utilizzo, questa condizione può causare problemi di simultaneità e risultati errati, soprattutto se le regole di sottoscrizione si basano su valori precedenti. Una sottoscrizione ordinata consente tuttavia di eseguire le sottoscrizioni in sequenza in base all'ordine di data e ora di un evento.
Per impostare questo comportamento, si utilizza la casella di controllo Esegui eventi in sequenza nella scheda Info sottoscrizione. Inoltre, una volta selezionato, uno sviluppatore acquisisce il controllo completo sul contenuto di un oggetto JSON dedicato per ogni sottoscrizione e questo gli consente di memorizzare i valori precedenti tra le esecuzioni di sottoscrizione, accumulare dati ed eseguire semplici aggregazioni con stato. Per ulteriori informazioni sull'utilizzo di thisSub.JSONState, vedere di seguito.
* 
Le sottoscrizioni ordinate richiedono più risorse della CPU rispetto a quelle non ordinate, pertanto contrassegnare tutte le sottoscrizioni come ordinate potrebbe influire sul consumo complessivo della CPU e ridurre la frequenza di esecuzione delle sottoscrizioni. Per le sottoscrizioni che non devono mantenere lo stato e possono essere eseguite in parallelo senza ripercussioni, è consigliabile lasciare deselezionata la casella di controllo Esegui eventi in sequenza.
Utilizzo di thisSub.JSONState
Questo oggetto, thisSub.JSONState, è accessibile tramite JavaScript, come descritto di seguito.
Per il valore nativo, utilizzare thisSub.JSONState.X=5.
Per l'infotable, utilizzare JSONObject(), thisSub.JSONstate.myInfoTable = Y.toJSONObject().
Per accedervi, utilizzare thisSub.state.myInfoTable.rows[0].value.
I dati memorizzati nell'oggetto JSONState devono essere utilizzati con attenzione e limitatamente ai campi necessari. Ad esempio, è preferibile evitare di memorizzare oggetti InfoTable completi utilizzando il metodo toJSONObject() anziché singoli campi, in quanto questa procedura richiede un utilizzo maggiore di CPU e di memoria di stato.
Per eliminare un valore dall'oggetto stato, utilizzare la parola chiave delete JavaScript delete thisSub.JSONState.myInfoTable.
Per cancellare l'intero oggetto stato, assegnarlo con un JSON vuoto {}:thisSub.JSONState = {}.
* 
Per evitare la perdita di dati degli stati dovuta a un consumo eccessivo di memoria, lo sviluppatore deve eliminare singoli campi di stato oppure cancellare l'intero oggetto thisSub.JSONState quando i dati memorizzati non sono più necessari.
thisSub.JSONState viene inserito in memoria e pertanto viene cancellato all'arresto di ThingWorx. Inoltre, lo stato viene cancellato quando:
L'entità che dichiara la sottoscrizione viene modificata e salvata.
L'entità che dichiara la sottoscrizione viene disattivata.
La sottoscrizione viene disattivata, ad esempio utilizzando il servizio DisableSubscription.
Il nuovo nodo ThingWorx viene avviato/interrotto in un cluster a disponibilità elevata e alcune sottoscrizioni iniziano a essere eseguite su un nodo diverso.
* 
ThingWorx impone limiti di dimensione della memoria sia per lo stato thisSub.JSONState di una singola sottoscrizione sia per l'archivio generale di tutti gli stati di sottoscrizione. La configurazione di questi limiti è illustrata nella sezione SubscriptionSettings dell'argomento Dettagli di configurazione di platform-settings.json.
Per ulteriori informazioni sul monitoraggio della memoria degli stati delle sottoscrizioni, vedere Prestazioni della sottoscrizione. Per informazioni sulle best practice relative alle sottoscrizioni, vedere Best practice in sintesi per la creazione di soluzioni ThingWorx.
Per un riepilogo sulle modalità di utilizzo delle sottoscrizioni a più eventi e delle sottoscrizioni ordinate, vedere Multi-Event Subscriptions in ThingWorx 9.5.
La sezione seguente, Casi di utilizzo, contiene esempi di codice che illustrano l'efficacia delle funzionalità di sottoscrizione a più eventi, ordinate e con stato, inclusi i casi d'uso relativi alla gestione delle collisioni per gli aggiornamenti delle proprietà e delle finestre temporali.
Casi di utilizzo
Caso di utilizzo 1 
// Usecase 1: alert will be triggered if voltage is higher than 118V
// Check if the voltage value exceeds 118 and trigger the appropriate action.
if (events["Me_DataChange_useCase1_Voltage"].eventData.newValue.value > 118){
logger.warn("Use-Case 1 subscription has been triggered");
}
Caso di utilizzo 2 
// Usecase 2: alert will be triggered if voltage is higher than 118V and current is lower than 2A

//********************** Default initialization ****************************************
if (thisSub.JSONState.Voltage === undefined)
thisSub.JSONState.Voltage = me.useCase2_Voltage; // default value from VTQ
if (thisSub.JSONState.Current === undefined)
thisSub.JSONState.Current = 0; // default value 0
//*************************************************************************************
//************************* storing the values in JSONState from eventData ***************
var aliasArray = Object.keys(events.dataShape.fields);
for (var i=0; i < aliasArray.length; i ++ ){
if (aliasArray[i] === "Me_DataChange_useCase2_Current")
// Assign the new current value to the state
thisSub.JSONState.Current = events["Me_DataChange_useCase2_Current"].eventData.newValue.value;
if (aliasArray[i] === "Me_DataChange_useCase2_Voltage") {
// Assign the new voltage value to the state
thisSub.JSONState.Voltage = events["Me_DataChange_useCase2_Voltage"].eventData.newValue.value;
}
}
//******************************************************************************************
// Check if both voltage and current meet the conditions - voltage is higher than 118V and current is lower than 2A
if (thisSub.JSONState.Voltage > 118 &&
thisSub.JSONState.Current < 2) {
logger.warn("Use-Case 2 alert !!!, Voltage is: "+thisSub.JSONState.Voltage+" and Current is: "+thisSub.JSONState.Current);
}
else
logger.warn("Use-Case 2 NO alert, Voltage is: "+thisSub.JSONState.Voltage+" and Current is: "+thisSub.JSONState.Current);
Caso di utilizzo 3 
// Usecase 3: alert will be triggered if voltage is higher than 118V and it has last more than 3 minutes.
// Timer will tick every X seconds

/*
When the DataChange event causing the subscription to run,
The value of Voltage will be checked:
1. If it would be above 118, timer would start running in case its undefined.
2. If it would be below or equal to 118, timer would back to undefined.
In case time has gotten to 3 minutes (180000MS), subscription would be triggered.
*/
// Getting the name of the event that triggered the subscription
let aliasArray = Object.keys(events.dataShape.fields);
if (aliasArray[0] === "Me_DataChange_useCase3_Voltage") {
// Valtage was changed
// We want to manage thisSub.JSONState.StartTime only. We don't save the Valtage in state

var Voltage = events[aliasArray[0]].eventData.newValue.value;

if( thisSub.JSONState.StartTime === undefined ) {
if( Voltage > 118 ){
thisSub.JSONState.StartTime = Date.now();
logger.warn("Voltage = " + Voltage + " Start time was set");
}
} else{
if( Voltage <= 118 ){
delete thisSub.JSONState.StartTime; // this will set to undefine
logger.warn("Voltage = " + Voltage + " Start time was unset");
}
}
}
else{
// We are in timer event
if( thisSub.JSONState.StartTime !== undefined && Date.now() - thisSub.JSONState.StartTime > 40000 )
logger.warn("Use-Case 3 timer was triggered - Alert !!! thisSub.JSONState.StartTime = " + thisSub.JSONState.StartTime);
else
logger.warn("Use-Case 3 timer was triggered - no Alert. thisSub.JSONState.StartTime = " + thisSub.JSONState.StartTime);
}

Caso di utilizzo 4 
// Usecase 4: Input 32 bit integer will be translated into 32 status properties if there is any change,
// and alert on status property potentially will be triggered.

logger.warn("Use-Case 4 subscription has been triggered");
Caso di utilizzo 5 
// Usecase 5: Alert will be triggered only on Error code which has severity level 1 or 2,
// where Error severity is defined in a relational table
// Get reference to the data table
var dataTable = Things["useCase5_DataTable"];
// Get the new value of ErrorCode from the event
var ErrorCodeValue = events["Me_DataChange_useCase5_ErrorCode"].eventData.newValue.value;
// Set parameters for querying the data table
var params = {
maxItems: 100, // Maximum number of entries to retrieve
source: undefined, // Filter entries by a specific source if needed
values: undefined, // Filter entries by specific column values if needed
orderBy: undefined // Order the retrieved entries by a specific column if needed
};
// Query the data table entries
var queryResult = dataTable.QueryDataTableEntries(params);
var rows = queryResult.rows;
// Iterate through the rows and check for matching ErrorCode and severity level
for (var i = 0; i < rows.length; i++) {
var thisRow = rows[i];

// Check if the ErrorCode matches the given ErrorCodeValue
if (thisRow.ErrorCode == ErrorCodeValue) {
// Check if the Severity is either 1 or 2
if (thisRow.Severity == 1 || thisRow.Severity == 2) {
// Log a warning message indicating the matched ErrorCode and its Severity
logger.warn("Error code: " + thisRow.ErrorCode + " has a severity of: " + thisRow.Severity + ". Use-Case 5 subscription has been triggered.");
}
}
}
Caso di utilizzo 6 
// Usecase 6: Alert will be trigged if sum of product count is less than 10 in past 10 minutes
// Timer will tick every 1 seconds (1000MS)

// Getting the name of the event that triggered the subscription
var alias = events.dataShape.fields;
// Check if the alias matches "Me_DataChange_useCase6_ProductCount"
if (alias == "Me_DataChange_useCase6_ProductCount") {
// Check if the productCountDict exists in the state
if (thisSub.JSONState.productCountDict != undefined) {
// Delete entries older than 10 minutes
deleteOlderThan10Minutes();
// Add a new entry with the current timestamp and the new value from the event
thisSub.JSONState.productCountDict[Date.now().toString()] = events[alias].eventData.newValue.value;
} else {
// Initialize the productCountDict as an empty object and add a new entry
thisSub.JSONState.productCountDict = {};
thisSub.JSONState.productCountDict[Date.now().toString()] = events[alias].eventData.newValue.value;
}
} else {
// Check if the startTime is undefined and set it to the current time
if (thisSub.JSONState.startTime == undefined) {
thisSub.JSONState.startTime = Date.now();
}
// Check if the productCountDict exists in the state
if (thisSub.JSONState.productCountDict != undefined) {
// Delete entries older than 10 minutes
deleteOlderThan10Minutes();
// Check if an alert should be triggered and log a warning message
if (shouldTriggerAlert()) {
logger.warn("Use-Case 6 subscription has been triggered");
}
}
}
// Function to delete entries older than 10 minutes from productCountDict
function deleteOlderThan10Minutes() {
var keys = Object.keys(thisSub.JSONState.productCountDict);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
// Check if the time difference is greater than 10 minutes (600,000 milliseconds)
if (Date.now() - parseInt(key) > 600000) {
delete thisSub.JSONState.productCountDict[key];
}
}
}
// Function to check if an alert should be triggered
function shouldTriggerAlert() {
// Check if the sum of product count is less than 10 and if the time difference is greater than 10 minutes
if (productCountDictSUM() < 10 && Date.now() - thisSub.JSONState.startTime > 600000) {
return true;
} else {
return false;
}
}
// Function to calculate the sum of values in productCountDict
function productCountDictSUM() {
var keys = Object.keys(thisSub.JSONState.productCountDict);
var sum = 0;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = thisSub.JSONState.productCountDict[key];
sum += value;
}
return sum;
}
Caso di utilizzo 7 
// Usecase 7: alert will be triggered if average current (5 minutes window) is higher than 2.5A,
// and it will be checked very 30 seconds.
// Timer will tick every 30 seconds (30000MS)
// Getting the name of the event that triggered the subscription
var alias = events.dataShape.fields;
// Checking if the data alias matches the expected value
if (alias == "Me_DataChange_useCase7_Current") {
// If the data dictionary exists, update it with the new current value
if (thisSub.JSONState.currentDict != undefined) {
deleteOlderThan5Minutes();
thisSub.JSONState.currentDict[Date.now().toString()] = events[alias].eventData.newValue.value;
} else {
// If the data dictionary doesn't exist, create it and set the start time
thisSub.JSONState.currentDict = {};
thisSub.JSONState.currentDict[Date.now().toString()] = events[alias].eventData.newValue.value;
}
} else {
if(thisSub.JSONState.startTime == undefined){
thisSub.JSONState.startTime = Date.now();
}
// If the data alias doesn't match, perform data management and potential alert triggering
if (thisSub.JSONState.currentDict != undefined) {
// Delete entries in the data dictionary older than 5 minutes
deleteOlderThan5Minutes();
// Check if conditions for triggering the alert are met
if (shouldTriggerAlert()) {
logger.warn("Use-Case 7 subscription has been triggered");
}
}
}
// Function to delete data entries older than 5 minutes
function deleteOlderThan5Minutes() {
var keys = Object.keys(thisSub.JSONState.currentDict);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (Date.now() - parseInt(key) > 300000) {
delete thisSub.JSONState.currentDict[key];
}
}
}
// Function to determine if the alert should be triggered
// Only in case 5 minutes has been passed, and AVG is higher then 2.5
function shouldTriggerAlert() {
if (currentDictAVG() > 2.5 && Date.now() - thisSub.JSONState.startTime > 300000) {
return true;
} else {
return false;
}
}
// Function to calculate the average of currentDict
function currentDictAVG() {
var keys = Object.keys(thisSub.JSONState.currentDict);
var sum = 0;
var count = 0;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = thisSub.JSONState.currentDict[key];
sum += value;
count++;
}
var average = sum / count;
return average;
}
////at any data change i sum the current
////when 30 seconds has been passed i calculate AVG
//
//
//
////change property event:
//// check if there is any value older then 5, if so - delete. (can implement by get keys)
//// add the value to the dict with key of timestamp
////timer event:
//// check if there is any value older then 5, if so - delete. (can implement by get keys)
//// AVG calculation, and condition check. - not only per 30 seconds, but for all the data at 5 minutes
//
//// build function to: change if there is any value older then 5, if so - delete. (can implement by get keys)
//
// ** the first timer event will be the startTime point of the algorithm
Caso di utilizzo 8 
// Usecase 8: the alert will be triggered when most recent value is greater than the previous 10 values
// Check if valuesArray state is undefined and initialize it
if (thisSub.JSONState.valuesArray === undefined) {
thisSub.JSONState.valuesArray = {};
}
// Check if valuesArray length is less than 10
let indexCounter = Object.keys(thisSub.JSONState.valuesArray).length;
if ( indexCounter < 3) {
// Add the new value to valuesArray
thisSub.JSONState.valuesArray["i" + indexCounter] = events["Me_DataChange_useCase8_prop"].eventData.newValue.value;
} else {
// The valuesArray is full

var max = 0;
// Find the maximum value in valuesArray
for (let i = 0; i < Object.keys(thisSub.JSONState.valuesArray).length; i++) {
if (thisSub.JSONState.valuesArray["i" + i] > max)
max = thisSub.JSONState.valuesArray["i" + i];
}

// Check if the new value is greater than the maximum value
if (events["Me_DataChange_useCase8_prop"].eventData.newValue.value > max)
logger.warn("Use-Case 8 Alert!!! max is " + events["Me_DataChange_useCase8_prop"].eventData.newValue.value);
// Shift the values in valuesArray by one position
for (var j = 0; j < parseInt((Object.keys(thisSub.JSONState.valuesArray)).length) - 1; j++) {
thisSub.JSONState.valuesArray["i" + j] = thisSub.JSONState.valuesArray["i" + (j + 1)];
}
// Add the new value to valuesArray using the current indexCounter
thisSub.JSONState.valuesArray["i" + (indexCounter - 1)] = events["Me_DataChange_useCase8_prop"].eventData.newValue.value;
}
logger.warn("Use-Case 8 End. valuesArray = " + thisSub.JSONState.valuesArray);
È stato utile?